【发布时间】:2014-05-20 17:51:44
【问题描述】:
处理流data.frame的最有效方法是什么
> df <- data.frame(amount=c(4,3,1,1,4,5,9,13,1,1), size=c(164,124,131,315,1128,331,1135,13589,164,68), tot=1, first=c(1,1,3,3,2,2,2,2,4,4), secs=c(2,2,0,0,1,1,1,1,0,0))
> df
amount size tot first secs
1 4 164 1 1 2
2 3 124 1 1 2
3 1 131 1 3 0
4 1 315 1 3 0
5 4 1128 1 2 1
6 5 331 1 2 1
7 9 1135 1 2 1
8 13 13589 1 2 1
9 1 164 1 4 0
10 1 68 1 4 0
按时间汇总
> df2
time tot amount size
1 1 2 3.5 144
2 2 6 34.5 16327
3 3 8 36.5 16773
4 4 2 2.0 232
.. 使用 R,当实际数据集可以超过 100 000 000 行甚至数十 GB 时?
列first 表示流的开始,持续时间为secs,指标为amount、size 和tot。在聚合总计中,size 和 amount 以双精度均匀地划分到时间范围,而 tot 以整数形式与每个时隙相加。持续时间secs 表示除了值first 之外,流持续了多少个时隙:如果secs 为 1,first 为 5,则流持续时隙 5 和 6。我当前的实现使用丑陋和死慢 for 循环,这不是一个选项:
df2 = data.frame()
for (i in 1:nrow(df)) {
items <- df[i, 'secs']
idd <- df[i, 'first']
for (ss in 0:items) { # run once for secs=0
if (items == 0) { items <- 1 }
df2[idd+ss, 'time'] <- idd+ss
if (is.null(df2[idd+ss, 'tot']) || is.na(df2[idd+ss, 'tot'])) {
df2[idd+ss, 'tot'] <- df[i, 'tot']
} else {
df2[idd+ss, 'tot'] <- df2[idd+ss, 'tot'] + df[i, 'tot']
}
if (is.null(df2[idd+ss, 'amount']) || is.na(df2[idd+ss, 'amount'])) {
df2[idd+ss, 'amount'] <- df[i, 'amount']/items
} else {
df2[idd+ss, 'amount'] <- df2[idd+ss, 'amount'] + df[i, 'amount']/items
}
if (is.null(df2[idd+ss, 'size']) || is.na(df2[idd+ss, 'size'])) {
df2[idd+ss, 'size'] <- df[i, 'size']/items
} else {
df2[idd+ss, 'size'] <- df2[idd+ss, 'size'] + df[i, 'size']/items
}
}
}
您可能可以仅使用循环对其进行大量优化并获得良好的性能,但我敢打赌,存在更好的算法。也许你可以以某种方式expand/duplicatesecs > 0 行,同时增加扩展行的first(时间戳)值并即时调整amount、size 和tot 指标:
now original data..
amount size tot first secs
1 4 164 1 1 0
2 4 164 1 1 1
3 3 124 1 1 2
magically becomes
amount size tot first
1 4 164 1 1
2 2 82 1 1
3 2 82 1 2
4 1 41.33 1 1
5 1 41.33 1 2
6 1 41.33 1 3
在此预处理步骤之后,使用plyr ddply 聚合将是微不足道的,当然在高效并行模式下。
我能够找到的所有示例 ddply、apply 等函数示例都以每行或每列为基础进行操作,因此很难修改其他行。希望我不必依赖 awk-magic。
更新:当扩展“按原样”完成时,上述算法很容易耗尽你的内存。因此,某种“动态”计算是首选,我们不会将所有内容映射到内存。然而,Mattrition 的答案是正确的并且帮助很大,因此将其标记为已接受的答案。
【问题讨论】:
-
你需要用简单的语言解释你是如何从问题中显示的输入到达输出的。
-
您当前的实现也有一些语法和其他错误。事实上,它不会产生任何输出。我什至看不出它会如何产生您建议的输出,因为您从未将任何内容分配给名为“时间”的列。
-
是的。添加了简要说明和“时间”分配。
-
还是不行。请尝试自己测试代码。
-
对原始的 for 循环进行了编辑以呈现功能。添加了所有美丽的整个代码。如果我们使用 row.names(df2) = "1" "2" "3" "4" 作为时间,您可以完全丢弃“时间”。