我正在尝试使用多个索引获取一组非常大的记录,计算由索引子集确定的组的聚合统计信息,然后将其插入表中的每一行。这里的问题是这些是非常大的表 - 每个超过10M行。
复制数据的代码如下。
基本思想是有一组索引,比如ix1,ix2,ix3,...,ixK。一般来说,我只选择其中几个,比如ix1和ix2。然后,我为一个名为val
的列计算所有行的聚合,其中匹配的ix1和ix2值(在所有出现的组合上)。为了简单起见,我将专注于一笔钱。
我尝试过以下方法
通过稀疏矩阵:将值转换为坐标列表,即(ix1,ix2,val),然后创建一个sparseMatrix - 这很好地总结了所有内容,然后我只需要从稀疏矩阵表示转换回来到坐标列表。速度:很好,但它的功能超出了必要的范围,并且不会推广到更高的尺寸(例如ix1,ix2,ix3)或更多的一般功能而不是总和。
使用lapply
和split
:通过创建一个对所有(ix1,ix2,...)n元组唯一的新索引,我可以使用split和apply 。这里的坏处是,唯一索引由split
转换为一个因子,这种转换非常耗时。试试system({zz <- as.factor(1:10^7)})
。
我现在正通过像data.table
这样的命令尝试sumDT <- DT[,sum(val),by = c("ix1","ix2")]
。但是,我还没有看到我如何将sumDT
与DT
合并,除了DT2 <- merge(DT, sumDT, by = c("ix1","ix2"))
这个data.table连接的方法是否比通过我所描述的merge
操作更快?
[我还尝试了bigsplit
包中的bigtabulate
以及其他一些方法。任何转换为因子的东西都非常多 - 据我所知,转换过程非常缓慢。]
生成数据的代码。当然,最好尝试使用较小的N
来查看某些内容有效,但并非所有方法都能很好地扩展N
&gt;&gt; 1000。
N <- 10^7
set.seed(2011)
ix1 <- 1 + floor(rexp(N, 0.01))
ix2 <- 1 + floor(rexp(N, 0.01))
ix3 <- 1 + floor(rexp(N, 0.01))
val <- runif(N)
DF <- data.frame(ix1 = ix1, ix2 = ix2, ix3 = ix3, val = val)
DF <- DF[order(DF[,1],DF[,2],DF[,3]),]
DT <- as.data.table(DF)
答案 0 :(得分:4)
嗯,只要你的key
被正确设置,你就会发现合并并不是那么糟糕。
让我们再次设置问题:
N <- 10^6 ## not 10^7 because RAM is tight right now
set.seed(2011)
ix1 <- 1 + floor(rexp(N, 0.01))
ix2 <- 1 + floor(rexp(N, 0.01))
ix3 <- 1 + floor(rexp(N, 0.01))
val <- runif(N)
DT <- data.table(ix1=ix1, ix2=ix2, ix3=ix3, val=val, key=c("ix1", "ix2"))
现在您可以计算摘要统计信息
info <- DT[, list(summary=sum(val)), by=key(DT)]
并合并“data.table方式”列,或仅合并merge
m1 <- DT[info] ## the data.table way
m2 <- merge(DT, info) ## if you're just used to merge
identical(m1, m2)
[1] TRUE
如果这些合并方式中的任何一种方法太慢,您可以尝试以内存为代价构建info
的棘手方法:
info2 <- DT[, list(summary=rep(sum(val), length(val))), by=key(DT)]
m3 <- transform(DT, summary=info2$summary)
identical(m1, m3)
[1] TRUE
现在让我们看看时间:
#######################################################################
## Using data.table[ ... ] or merge
system.time(info <- DT[, list(summary=sum(val)), by=key(DT)])
user system elapsed
0.203 0.024 0.232
system.time(DT[info])
user system elapsed
0.217 0.078 0.296
system.time(merge(DT, info))
user system elapsed
0.981 0.202 1.185
########################################################################
## Now the two parts of the last version done separately:
system.time(info2 <- DT[, list(summary=rep(sum(val), length(val))), by=key(DT)])
user system elapsed
0.574 0.040 0.616
system.time(transform(DT, summary=info2$summary))
user system elapsed
0.173 0.093 0.267
或者你可以跳过中间info
表格构建,如果以下内容对你的口味看起来不太难以理解:
system.time(m5 <- DT[ DT[, list(summary=sum(val)), by=key(DT)] ])
user system elapsed
0.424 0.101 0.525
identical(m5, m1)
# [1] TRUE