【发布时间】:2016-08-28 12:11:57
【问题描述】:
我想重塑一个 data.table,并包含每个变量的历史(累计)信息。 No 变量表示对象ID 的测量时间顺序。在每次测量中都会发现附加信息。我想在每个时间戳 No 为对象 ID 聚合已知信息。
让我用一个例子来演示:
对于以下data.table:
df <- data.table(ID=c(1,1,1,2,2,2,2),
No=c(1,2,3,1,2,3,4),
Variable=c('a','b', 'a', 'c', 'a', 'a', 'b'),
Value=c(2,1,3,3,2,1,5))
df
ID No Variable Value
1: 1 1 a 2
2: 1 2 b 1
3: 1 3 a 3
4: 2 1 c 3
5: 2 2 a 2
6: 2 3 a 1
7: 2 4 b 5
我想把它改造成这样:
ID No a b c
1: 1 1 2 NA NA
2: 1 2 2 1 NA
3: 1 3 5 1 NA
4: 2 1 NA NA 3
5: 2 2 2 NA 3
6: 2 3 3 NA 3
7: 2 4 3 5 3
所以 Value 的总和值,每个 Variable 乘以 (ID, No),累积超过 No。
我可以通过做没有累积部分得到结果
dcast(df, ID+No~Variable, value.var="Value")
导致非累积变体:
ID No a b c
1: 1 1 2 NA NA
2: 1 2 NA 1 NA
3: 1 3 3 NA NA
4: 2 1 NA NA 3
5: 2 2 2 NA NA
6: 2 3 1 NA NA
7: 2 4 NA 5 NA
任何想法如何使这种累积?原始 data.table 有超过 250,000 行,因此效率很重要。
编辑:我只是以 a,b,c 为例,原始文件有大约 40 个不同的级别。此外,NAs 很重要;还有Value-values 为0,这意味着不是NA
可能的解决方案
好的,我找到了一个可行的解决方案。它远没有效率,因为它扩大了原始表格。
这个想法是复制每一行TotalNo - No 次,其中TotalNo 是每个ID 的最大值No。然后可以使用原始的 dcast 函数来提取数据帧。所以在代码中:
df[,TotalNo := .N, by=ID]
df2 <- df[rep(seq(nrow(df)), (df$TotalNo - df$No + 1))] #create duplicates
df3 <- df2[order(ID, No)]#, No:= seq_len(.N), by=.(ID, No)]
df3[,No:= seq(from=No[1], to=TotalNo[1], by=1), by=.(ID, No)]
df4<- dcast(df3,
formula = ID + No ~ Variable,
value.var = "Value", fill=NA, fun.aggregate = sum)
这不是很好,因为创建重复项会占用更多内存。我认为它可以进一步优化,但到目前为止它适用于我的目的。在示例代码中,它从 7 行变为 16 行,在原始文件中从 241,670 行变为高达 978,331 行。这比原来大 4 倍多。
解决方案 Eddi 改进了我在整个数据集中计算时间的解决方案(Eddi 的 2.08 秒,而我的 4.36 秒)。这些是我可以使用的数字!谢谢大家!
【问题讨论】:
-
如果你不介意用零代替
NAs,你可以使用cols <- sort(unique(df$Variable)) ; res <- dcast(df, ID + No ~ Variable, value.var = "Value", fill = 0L)[, (cols) := lapply(.SD, cumsum), .SDcols = cols, by = ID] -
零不是一个选项;还有一些值 0 与 NA 具有不同的含义。感谢您的贡献!
标签: r data.table