我有一个老问题,因为数据集的大小而具有挑战性。问题是将数据帧从长矩阵转换为宽矩阵:
set.seed(314)
A <- data.frame(field1 = sample(letters, 10, replace=FALSE),
field2 = sample(toupper(letters), 10, replace=FALSE),
value=1:10)
B <- with(A, tapply(value, list(field1, field2), sum))
这也可以通过基础R中的旧重塑来完成,或者更好地在plyr和reshape2中完成。在普利尔:
daply(A, .(field1, field2), sum)
在reshape2中:
dcast(A, field1 ~ field2, sum)
问题是我的数据帧有30 + m行,field1至少有5000个唯一值,field2有20000个唯一值。有了这个尺寸,plyr崩溃,重塑2偶尔崩溃,并且tapply非常慢。该机器不是约束(48GB,<50%利用率和8核Xeon)。这项任务的最佳实践是什么?
N.B。:这个问题不重复。我明确提到输出应该是一个宽数组。作为重复引用的答案引用dcast.data.table的使用,它返回data.table。将data.table转换为数组是一项非常昂贵的操作。
答案 0 :(得分:3)
FWIW,这是部分使用data.table
的解决方案(仅用于聚合)。
(编辑:我用@BenBolker的答案替换了dcast.data.table
答案,因为它完全避免了这一步骤,并且内存和速度都很高效 - 请检查修订版本是否为&#39 ;重新寻找解决方案)。
require(data.table) ## >= 1.9.2
set.seed(1L)
N = 30e6L
DT <- data.table(field1 = sample(paste0("F1_", 1:5000), N, TRUE),
field2 = sample(paste0("F2_", 1:20000), N, TRUE),
value = sample(10))
> tables()
# NAME NROW MB COLS KEY
# [1,] DT 30,000,000 574 field1,field2,value
# Total: 574MB
system.time(ans <- DT[, list(value=sum(value)), by=list(field1, field2)])
# user system elapsed
# 15.097 3.357 18.454
(已编辑的答案:)然后您可以使用@ BenBolker(聪明)解决方案,如下所示(这完全无需cast
):
system.time({
rlabs <- sort(unique(ans$field1))
clabs <- sort(unique(ans$field2))
fans <- matrix(NA,length(rlabs),length(clabs),
dimnames=list(rlabs,clabs))
fans[as.matrix(ans[,1:2, with=FALSE])] <- ans$value
})
# user system elapsed
# 18.630 1.524 20.154
答案 1 :(得分:2)
我没有检查速度,但是这种低级方法更好吗? (设置一个带有适当边距的NA
s的矩阵,并使用2列矩阵索引填写......)
rlabs <- sort(unique(A$field1))
clabs <- sort(unique(A$field2))
B <- matrix(NA,length(rlabs),length(clabs),
dimnames=list(rlabs,clabs))
B[as.matrix(A[,1:2])] <- A[,3]
如果您可以将其设置为稀疏矩阵,那将非常好,但我假设您的value
列中的值为零...