从长数据帧到宽数组的快速转换

Posted

技术标签:

【中文标题】从长数据帧到宽数组的快速转换【英文标题】:Fast transformation from long data frame to wide array 【发布时间】:2014-05-16 02:24:32 【问题描述】:

我有一个因数据集大小而变得具有挑战性的老问题。问题是将数据帧从长矩阵转换为宽矩阵:

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))

这也可以通过 base R 中的旧 reshape 来完成,或者在 plyr 和 reshape2 中更好。在 plyr 中:

daply(A, .(field1, field2), sum)

在重塑2中:

dcast(A, field1 ~ field2, sum)

问题是我的数据框有 30+m 行,field1 至少有 5000 个唯一值,field2 至少有 20000 个唯一值。使用这个大小,plyr 崩溃,reshape2 偶尔崩溃,并且 tapply 非常慢。机器不受限制(48GB、

注意:这个问题不是重复的。我明确提到输出应该是一个宽 array。作为重复引用的答案引用了 dcast.data.table 的使用,它返回一个 data.table。将 data.table 转换为数组是一项非常昂贵的操作。

【问题讨论】:

你见过:***.com/questions/18802257/… 或 ***.com/questions/6902087/… 吗? 希望我的“金锤”重复标记没有为时过早...... +mnel,见上面的评论。这不是重复的问题。 【参考方案1】:

FWIW,这是部分使用 data.table 的解决方案(仅用于聚合)。

(编辑:我将dcast.data.table 的答案替换为@BenBolker 的答案,因为它完全避免了该步骤,并且内存和速度都有效 - 如果您正在寻找,请检查修订该解决方案)。

创建一些示例数据(具有类似的规范):

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(聪明)的解决方案如下(完全不需要casting):

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

【讨论】:

谢谢,我会介绍的。目前我做一个 dcast.data.table 后跟一个 data.matrix (和一些小的转换)。这应该更快。【参考方案2】:

我没有检查速度,但是这种低级方法更好吗? (设置一个充满NAs 的矩阵并带有适当的边距,并使用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 列中的值为零...

【讨论】:

以上是关于从长数据帧到宽数组的快速转换的主要内容,如果未能解决你的问题,请参考以下文章

使用熊猫将数据帧从长到宽转换-单行输出

Mysql,重塑数据从长/高到宽

athena presto - 从长到宽的多列

tidyR 从长到宽的数据?

熊猫从长到宽重塑,由两个变量

从长到宽重塑并创建具有二进制值的列