2014-12-19 67 views
2

我正在嘗試dcast大型數據集(數百萬行)。我有一排到達時間和出發地,另一排出發時間和目的地。在兩種情況下都有一個id來標識單位。它看起來類似於這樣:dcast有效地使用多個變量的大型數據集

id time   movement origin dest 
1 10/06/2011 15:54 ARR  15 15 
1 10/06/2011 16:14 DEP  15 29 
2 10/06/2011 17:59 ARR  73 73 
2 10/06/2011 18:10 DEP  73 75 
2 10/06/2011 21:10 ARR  75 75 
2 10/06/2011 21:20 DEP  75 73 
3 10/06/2011 17:14 ARR  17 17 
3 10/06/2011 18:01 DEP  17 48 
4 10/06/2011 17:14 ARR  49 49 
4 10/06/2011 17:26 DEP  49 15 

所以,我想重新分配對(ARR - DEP),有效地做到這一點(如here)。由於這是一個非常大的數據集,因此for loop在這種情況下不起作用。理想的輸出將

index unitid origin arr time dest dep time 
    1 1  15 10/06/2011 14:33 29 10/06/2011 19:24 
    2 2  73 10/06/2011 14:59 75 10/06/2011 17:23 
    3 2  75 10/06/2011 21:10 73 10/06/2011 23:40 

數據:

 df <- structure(list(time = structure(c(7L, 16L, 8L, 11L, 18L, 20L, 
10L, 12L, 3L, 6L, 15L, 19L, 9L, 4L, 5L, 14L, 1L, 2L, 13L, 17L 
), .Label = c("10/06/2011 09:08", "10/06/2011 10:54", "10/06/2011 11:38", 
"10/06/2011 12:41", "10/06/2011 12:54", "10/06/2011 14:26", "10/06/2011 14:33", 
"10/06/2011 14:59", "10/06/2011 17:12", "10/06/2011 17:14", "10/06/2011 17:23", 
"10/06/2011 18:56", "10/06/2011 19:03", "10/06/2011 19:04", "10/06/2011 19:16", 
"10/06/2011 19:24", "10/06/2011 20:12", "10/06/2011 21:10", "10/06/2011 22:28", 
"10/06/2011 23:40"), class = "factor"), movement = structure(c(1L, 
2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 3L, 1L, 2L, 2L, 1L, 
2L, 2L, 3L), .Label = c("ARR", "DEP", "ITZ"), class = "factor"), 
    origin = c(15L, 15L, 73L, 73L, 75L, 75L, 17L, 17L, 49L, 49L, 
    15L, 15L, 32L, 10L, 10L, 17L, 76L, 76L, 76L, 76L), dest = c(15L, 
    29L, 73L, 75L, 75L, 73L, 17L, 48L, 49L, 15L, 15L, 49L, 32L, 
    10L, 17L, 10L, 76L, 65L, 76L, 65L), id = c(1L, 1L, 2L, 2L, 
    2L, 2L, 3L, 3L, 4L, 4L, 4L, 4L, 5L, 6L, 6L, 6L, 7L, 7L, 8L, 
    8L)), .Names = c("time", "movement", "origin", "dest", "id" 
), row.names = c(NA, -20L), class = "data.frame") 
+0

也許你可以試試'從dcast.data.table' [1.9.8的分支 「data.table」( https://github.com/Rdatatable/data.table/tree/1.9.8)(但是期望事情可能會改變,因爲那還不是CRAN的版本 – A5C1D2H2I1M1N2O1R2T1 2014-12-19 10:45:41

+0

嗨@AnandaMahto,如果我只是想挑選時間,此代碼(通過@akron)在'dcast.data.table(setDT(df)[,c('。id','Seq'):= list(c('arrival','departure')) gl(.N,2,.N))],id + Seq〜.id,value.var ='time')'但是,如果我想添加原點和des tination的信息,我真的不知道如何撿起來。請記住它是一個非常大的數據集(百萬行) – user3507584 2014-12-19 11:37:32

+0

您能告訴我們您要處理的行數有多少? – Arun 2014-12-19 12:34:02

回答

3

這個怎麼樣?使用data.table

require(data.table) 
setorder(setDT(df), id, time) 
df[, grp := FALSE][movement == "ARR", grp := TRUE] 
df[, .(time[grp], time[!grp], origin[grp], dest[!grp]), by=id] 
# id     V1     V2 V3 V4 
# 1: 1 10/06/2011 14:33:57 10/06/2011 19:24:16 15 29 
# 2: 2 10/06/2011 14:59:14 10/06/2011 17:23:20 73 75 
# 3: 2 10/06/2011 21:10:56 10/06/2011 23:40:29 75 73 
# 4: 3 10/06/2011 17:14:44 10/06/2011 18:56:39 17 48 
# 5: 4 10/06/2011 11:38:43 10/06/2011 14:26:43 49 15 
# 6: 4 10/06/2011 19:16:55 10/06/2011 22:28:14 15 49 
# 7: 5 10/06/2011 10:41:20 10/06/2011 12:54:26 10 17 
# 8: 6 10/06/2011 09:08:05 10/06/2011 10:54:48 76 65 

可以使這個速度稍快,如果你與價值!grp添加另一列,並使用該列,而不是對每個組做!grp


這是如何工作:

  • setDT參照data.frame轉換爲data.table。

  • setorder根據提供的列(和順序)通過引用重新排序data.table。在此,根據列idtime以遞增順序重排df的行。

  • 然後我們使用data.table的參照子分配增加持有價值TRUEmovement == "ARR"FALSEmovement == "DEP"一個額外的列。

    注意:df$movement列中的因子級別有一個額外的級別,稱爲ITZ,似乎不在此示例數據中。不知道如何處理。

  • 現在我們要做的就是選擇1,3,5,...從origin和2,4,6元素,...從dest(以及類似的time)元素。

這隻要ARR時間總是DEP時間(這是非常有效的假設)以前一樣工作。


繼OP的編輯到Q與數據不一致:

na.omit(df[movement != "ITZ", .(time[grp], time[!grp], origin[grp], dest[!grp]), by=id]) 
+1

擁有620萬行,時間爲:'setorder(setDT(df),id,time)'0.25秒,'df [,grp:= FALSE] [movement ==「ARR」,grp:= TRUE]'0.53秒,'df [,。(時間[grp],時間[!grp],原點[grp], dest [!grp]),by = id]'6.52秒。總計:7.3秒,因此每秒鐘處理將近一百萬(900k)行。非常感謝@Arun – user3507584 2014-12-19 14:57:34

+1

@Arun這是很棒的解決方案。 – akrun 2014-12-19 15:39:30

1

如果數據集的結構類似的例子,即存在一個到達,每個ID和原產地一個出發時間,那麼你可以要手動完成此操作,只需對數據進行重新排序和子集化(當然,您必須對此非常小心,並嘗試添加儘可能多的檢查,如下所示,以便發現錯誤)

dat <- df[order(df$id, df$origin, df$dest, df$movement), ] 
dat.dep <- dat[dat$movement == "DEP", ] 
dat.arr <- dat[dat$movement == "ARR", ] 
stopifnot(nrow(dat.dep) == nrow(dat.arr) & 
    dat.dep$origin == dat.arr$origin & 
    dat.dep$id == dat.arr$id) 
result <- dat.dep[c("id", "origin", "dest")] 
result$arr.time <- dat.arr$time 
result$dep.time <- dat.dep$time 
result 
# id origin dest   arr.time   dep.time 
# 2 1  15 29 10/06/2011 14:33:57 10/06/2011 19:24:16 
# 4 2  73 75 10/06/2011 14:59:14 10/06/2011 17:23:20 
# 6 2  75 73 10/06/2011 21:10:56 10/06/2011 23:40:29 
# 8 3  17 48 10/06/2011 17:14:44 10/06/2011 18:56:39 
# 12 4  15 49 10/06/2011 19:16:55 10/06/2011 22:28:14 
# 10 4  49 15 10/06/2011 11:38:43 10/06/2011 14:26:43 
# 14 5  10 17 10/06/2011 10:41:20 10/06/2011 12:54:26 
# 16 6  76 65 10/06/2011 09:08:05 10/06/2011 10:54:48 
+0

@阿倫我明白這一點。並非每個數據點都由其ID,起源和運動獨特地確定? – konvas 2014-12-19 16:02:13

+1

@現在我明白了。所以問題出在我的措辭上。我沒有在解決方案中假設這一點,但我的意思是一個到達和一個離開每個ID和起源..謝謝:) – konvas 2014-12-19 16:27:11

相關問題