R 中的高效数据 table/ frame/ tibble/ 其他聚合

Efficient data table/ frame/ tibble/ other aggregation in R

我有一个 data.table 个值,我在循环中为其计算汇总统计信息,并寻求汇总汇总结果以进行额外处理。但是,聚合后的循环处理时间出乎意料的长,我正在寻求更快的解决方案。

该方法与此处讨论的方法非常相似 ()。

代码(为了便于阅读而略有删节,但 material 保留了组件 说明):

library(data.table);
x <- data.table(matrix(double(),nrow=10000,ncol=120));
system.time({for (i in NROW(x):1) {
    m <- matrix(rnorm(8*15),nrow=8,ncol=15);
}});
#  user  system elapsed 
# 0.165   0.006   0.171 
system.time({for (i in NROW(x):1) {
    m <- matrix(rnorm(8*15),nrow=8,ncol=15);
    as.list(t(m[1:8,]));
}});
#   user  system elapsed 
#  0.245   0.001   0.249
system.time({for (i in NROW(x):1) {
    m <- matrix(rnorm(8*15),nrow=8,ncol=15);
    x[i,] <- as.list(t(m[1:8,]));
}});
#   user  system elapsed 
# 36.227   0.682  37.529

# Obtain input data.table
inputdt <- fread('filename');

# Preallocate summary statistics aggregate
sumstatsdt <- data.table(matrix(double(),nrow=10000,ncol=120));

# Loop over input data.table (the *apply suite not suitable for mypkg::calcstats())
for (i in NROW(inputdt):1) {
    # Produce a matrix of summary statistics for the row (of type double)
    sumstat_matrix <- mypkg::calcstats(inputdt,...);

    # Aggregate the summary statistics (where "a","b","c",... are matrix row names of ordered statistics)
    # >>>> This is the operation that leads to lengthy execution time
    sumstatsdt[i,] <- as.list(t(sumstat_matrix[c("a","b","c",...),]));
};

输入 data.table 包含 10,000 个具有 8 个属性的观察值,总共要存储 120 万个摘要统计信息(每个类型 'double')。注释掉执行聚合的循环中的最后一行时,总处理时间约为 24 秒。当 运行 进行聚合时,总处理时间增加到 34 分钟

我曾尝试将可比较的代码与 data.framecbind() 一起使用,性能结果大致相似(还没有机会尝试 tidyverse 套件)。认识到深度复制操作会稍微慢一些,尽管鉴于相对较小的数据集执行时间差异的幅度似乎表明不同的问题。

运行 R v3.4.4,data.table v1.11.4 最近的 Fedora 安装。内存使用可以忽略不计(在 R 脚本执行期间使用的系统 RAM 不到 3%)。在脚本执行期间,与 R 会话 运行 亲和力接近 100% 的 2.1GHz CPU 处理器之一。没有其他进程与该核心关联,其余核心大部分处于闲置状态。 (注意:不同机器上 KVM guest 中的说明性代码 运行)

旁注:也很好奇为什么 CPU 瓶颈表现为内存问题。

珍惜时间,很高兴提供有用的额外信息。

编辑 [2018.10.31]

你的机器似乎比我的快两倍,但我仍然通过使用 data.table 运算符 := 而不是 <-。我不确定,但怀疑使用 <- 会让您依赖创建中间临时副本的通常 R 步骤,因此 := 方法可能也更节省内存:

?`:=`

 system.time({for (i in NROW(x):1) {
     m <- matrix(rnorm(8*15),nrow=8,ncol=15);
     x[i , (1:120) := as.list(t(m))] } })

 #   user  system elapsed 
 # 4.390   0.096   4.486 


system.time({for (i in NROW(x):1) {
     m <- matrix(rnorm(8*15),nrow=8,ncol=15);
     x[i , ] <- as.list(t(m)) } })

#   user  system elapsed 
# 67.963  15.573  83.572 

常规 R 是单线程进程,除非您安装了 "after-market" 模组之一,例如 MRAN。