跨表相乘时如何加速我的 R 代码?

How can I speed up my R code when multiplying across tables?

这是我正在尝试做的一个例子。

dtA <- data.table(A = 1:3, B = 4:6, D = 7:9)
dtB <- data.table(id = c("A", "B", "C", "D"), multi = c(0.1, 0.2, 0.3, 0.4))


for(COL in c("A", "B", "D")) {
  dtA[, (COL) := get(COL) * dtB[id == COL, multi]] 
}

我需要使用 dtB 中的 id 列将 dtA 中的列乘以乘数,以确定要将哪一列乘以哪个因子。我可以用 for 循环来做,但它很慢。我会喜欢任何关于如何提高效率的建议。感谢您的帮助!

这是一个 data.table 方法..可能不是最好的方法..但它完成了工作。

library( data.table )
#melt dtA to long format
dtA.melt <- melt( dtA, measure.vars = names(dtA), variable.factor = FALSE)
#set integers to numeric
dtA.melt[, value := as.numeric(value)]
#update the value column using a join
dtA.melt[ dtB, value := as.numeric(value) * i.multi, on = .(variable = id)]
#and bind back the columns
do.call( cbind, split( dtA.melt, by = "variable", keep.by = FALSE ) )

#    A.value B.value D.value
# 1:     0.1     0.8     2.8
# 2:     0.2     1.0     3.2
# 3:     0.3     1.2     3.6

觉得这个比你的方法快一点

vec <- dtB[colnames(dtA), multi, on = 'id']
dtA <- as.data.table(mapply(function(x,y) x*y, dtA, vec, SIMPLIFY = FALSE))

虽然我真的看不出在哪里可以显着提高速度,因为我认为您在尝试时没有做任何特别浪费的事情。

编辑:

对于较大的示例,这又快了大约 50%

cn <- colnames(dtA)
dtA[,(cn) := mapply(function(x,y) x*y, dtA, dtB[cn, multi, on = 'id'], SIMPLIFY = FALSE)]

这是基本的 R 方法

as.data.table(t(t(dtA) * with(dtB, multi[match(names(dtA),id)])))

这给出了

     A   B   D
1: 0.1 0.8 2.8
2: 0.2 1.0 3.2
3: 0.3 1.2 3.6

使用旨在快速计算乘积然后以 data.table 或其他格式存储结果的库可能会为您提供最好的服务。例如,'Rfast' 针对矩阵的数值计算进行了优化。 R 'data.table' 非常擅长存储和检索大型数据表,但默认情况下存储为 (R) 列表:

library(data.table)
library(Rfast)

# https://rdrr.io/cran/Rfast/man/
# https://github.com/RfastOfficial/Rfast
# install.packages("Rfast")

x <- matrnorm(10^7,2)

dt <- setnames(as.data.table(cbind(x,prod=rowprods(x))),c("mult1","mult2","prod"))[]

object.size(dt)
240001544 bytes
dt
               mult1      mult2       prod
       1: -0.8085044 -1.9285537  1.5592442
       2: -1.5677905 -1.5577447  2.4422173
       3:  0.5049556 -0.2790959 -0.1409310
       4: -0.4603246  0.7289480 -0.3355527
       5:  1.4131808 -1.0857271 -1.5343287
      ---                                 
 9999996:  0.2373198 -0.7700162 -0.1827401
 9999997: -1.4357042  0.9946241 -1.4279859
 9999998:  1.1464551  0.1137755  0.1304385
 9999999:  0.3204307 -0.9189214 -0.2944506
10000000:  1.5800871 -1.3029509 -2.0587759

x <- matrnorm(10^7,2)
system.time(setnames(as.data.table(cbind(x,prod=rowprods(x))),c("mult1","mult2","prod"))[])
       user  system elapsed 
       0.12    0.08    0.21