我正在尝试dcast
一个大型数据集(数百万行)。我有一排到达时间和起点,另一排是出发时间和目的地。在两种情况下都有id
来标识单位。它看起来与此相似:
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 :(得分: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。在此,它会根据列df
和id
按递增顺序重新排序time
行。
然后我们使用data.table的按引用进行子分配来添加一个额外的列,该列在TRUE
和movement == "ARR"
时保存值FALSE
何时movement == "DEP"
。
注意:df$movement
列中的因子级别有一个名为ITZ
的附加级别,该级别似乎不在此示例数据中。不知道如何处理。
现在我们所要做的就是从origin
中选择1,3,5,...元素和从dest
中选择2,4,6,......元素(同样适用于time
)。
只要ARR
时间总是在DEP
时间之前(这是一个非常有效的假设),这就有效。
在OP编辑Q后,数据不一致:
na.omit(df[movement != "ITZ", .(time[grp], time[!grp], origin[grp], dest[!grp]), by=id])
答案 1 :(得分: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