如何大幅提升R data.table连接+分组+汇总操作的速度?
性能优化求助:大规模线性方程组场景计算提速
实际业务问题概述
这本质是线性方程组的场景评估问题,涉及两个data.table:
s_dt包含各观测场景(o)的场景信息、驱动变量(d)及对应数值(v);c_dt包含多个拟合模型基(b)的系列项(n),驱动变量的幂次及相关系数以键值对形式存储在d和t中,每个模型基b本质是含n个项的多项式。
现存问题
下方复现案例可生成预期输出格式,但即使是简化版问题,运行速度也远无法满足需求。测试数据为模拟值,但真实数据的耗时表现类似:
在12线程系统上,“小型”问题耗时约3秒,而“大型”问题规模是其4000倍,预计耗时约3小时。目标是将大型问题的运行时间压缩至5分钟以内(越快越好)
恳请指点:如何大幅提升运行速度?慢因是什么?
若base/tidyverse方案能满足性能需求也可接受,原以为data.table是处理该规模问题的最优选择。
当前解决方案
对s_dt按o分组,在每组上执行fun函数:fun函数的逻辑是将c_dt与分组数据连接,填充v字段,进而计算多项式方程的结果r。
data.table语法实现:
s_dt[, fun(.SD), keyby = .(o)]
复现案例
- 生成两个结构、字段类型与真实数据匹配的
data.table,仅缩小规模用于演示; - 定义
fun函数并运行,计算所有场景的r值。
library(data.table) # 问题规模设置 ---- dims <- list(o = 50000, d = 50, b = 250, n = 200) # "大型"问题——真实业务规模 dims <- list(o = 100, d = 50, b = 25, n = 200) # "小型"问题(缩短示例运行时间) # 构建测试data.table ---- build_s <- function() { o <- seq_len(dims$o) d <- paste0("d",seq_len(dims$d)) v <- as.double(seq_len(dims$o * dims$d))/10000 CJ(o, d)[, `:=`(v = v)] } s_dt <- build_s() build_c <- function() { b <- paste0("c", seq_len(dims$b)) n <- seq_len(dims$n) d <- c("c", paste0("d", seq_len(dims$d))) t <- as.double(rep_len(0:6, dims$b * dims$n * (dims$d+1))) dt <- CJ(d, b, n)[, `:=`(t = t)] dt <- dt[t != 0] } c_dt <- build_c() # 定义函数并执行 ---- # (此部分需优化) profvis::profvis({ fun <- function(dt) { # 此处不使用链式调用,以便获得更有效的profvis分析结果 dt <- dt[c_dt, on = .(d)] dt <- dt[, r := fcase(d == "c", t, is.na(v), 0, rep(TRUE, .N), v^t)] dt <- dt[, .(r = prod(r)), keyby = .(b, n)] dt <- dt[, .(r = sum(r)), keyby = .(b)] } res <- s_dt[, fun(.SD), keyby = .(o)] })
输入输出示例
> res o b r 1: 1 c1 0.000000e+00 2: 1 c10 0.000000e+00 3: 1 c11 0.000000e+00 4: 1 c12 0.000000e+00 5: 1 c13 0.000000e+00 --- 2496: 100 c5 6.836792e-43 2497: 100 c6 6.629646e-43 2498: 100 c7 6.840915e-43 2499: 100 c8 6.624668e-43 2500: 100 c9 6.842608e-43 > s_dt o d v 1: 1 d1 0.0001 2: 1 d10 0.0002 3: 1 d11 0.0003 4: 1 d12 0.0004 5: 1 d13 0.0005 --- 4996: 100 d50 0.4996 4997: 100 d6 0.4997 4998: 100 d7 0.4998 4999: 100 d8 0.4999 5000: 100 d9 0.5000 > c_dt d b n t 1: c c1 2 1 2: c c1 3 2 3: c c1 4 3 4: c c1 5 4 5: c c1 6 5 --- 218567: d9 c9 195 5 218568: d9 c9 196 6 218569: d9 c9 198 1 218570: d9 c9 199 2 218571: d9 c9 200 3
内容的提问来源于stack exchange,提问作者mb147
相关产品推荐
相关产品推荐

