你提到你的数据维度是 2000 万行,12 列,但没有提到“ID”的唯一值的数量。我在这里假设为 20,000。
如果您正在寻找 1) 快速和 2) 内存高效的解决方案,那么 Matthew 的(或 Jeremy 的)拼出所有变量的解决方案会表现得更好——也就是说,直到unlist(.SD)
被优化。基本上最好的是@codoremifa 的语法与@Matthew 的性能。
这篇文章的目的是说明在聚合之前(在如此巨大的维度setkey
上data.table
)可以获得的性能增益(在撰写本文时,答案尚未涵盖该方面)。
setkey
通常使用它,因为它是join
或fast subset
(基于二分搜索)是必需的。但是在诸如您的数据维度(可以肯定地说,大数据)上,您可以通过设置密钥受益很多。这是因为,setkey
按您的键列对数据进行排序,这允许列在以后聚合到连续的内存位置,因此非常有效。
v1.8.11(当前的开发版本,setkey
也变得更快了)有很多增强功能。因此,此处显示的基准将随CRAN 上的当前稳定版本 1.8.10而变化。如果你不使用开发版也没关系。希望这会让您相信它的有用性,setkey
并为您提供一些关于下一个版本的预期内容。
好的,继续说明您的尺寸数据:
获取一些数据:
require(data.table)
set.seed(1L)
uval <- 2e4 # unique values in ID
N <- 20e6
DT <- data.table(ID=sample(uval, N, TRUE)) # for simplicity ID is integer
cols <- paste("V", 1:11, sep="")
set(DT, i=NULL, j=cols, value=as.list(1:11))
dim(DT) # 20e6 by 12
不设置键:
system.time(ans1 <- DT[,
list(val=mean(c(V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11))),
by=ID])
# user system elapsed
# 45.587 0.632 46.251
通过设置键:
system.time(setkey(DT, ID)) # (note that this'll be much faster on 1.8.11)
# user system elapsed
# 5.872 0.072 5.948
system.time(ans2 <- DT[,
list(val=mean(c(V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11))),
by=ID])
# user system elapsed
# 2.164 0.236 2.400
setkey(ans1, ID)
identical(ans1, ans2) # [1] TRUE
您会看到,通过设置密钥,您需要约 8.4 秒,而没有它的情况是 > 40 秒。这是一个很大的加速。