将数据帧乘以向量的最有效方法

Thi*_*lbo 2 r

将数据帧的每一列乘以向量的最有效方法是什么?

例如,数据框 ( df) 具有以下列 ( col1, col2, col3, col4),向量 ( v) 具有以下元素 ( v1,v2,v3)。

我希望输出是: col2*v1, col3*v2, col4*v3

我一直在尝试,df[c(2:4)] * c(v1,v2,v3)但似乎向量的元素没有乘以每列的每一行。

jos*_*ber 5

您可以尝试(使用dfv来自理查德斯克里文的回答):

df[-1] <- t(t(df[-1]) * v)
df
#   a  x  y   z
# 1 a  5 40 105
# 2 b 10 50 120
# 3 c 15 60 135
Run Code Online (Sandbox Code Playgroud)

当您将矩阵乘以向量时,它会按列相乘。由于您想将行乘以向量,因此我们df[-1]使用转置t,乘以v,然后使用 转回t

似乎这种方法在基准测试方面比该Map方法略有优势,并且比sweep

library(microbenchmark)
rscriven <- function(df, v) cbind(df[1], Map(`*`, df[-1], v))
josilber <- function(df, v) cbind(df[1], t(t(df[-1]) * v))
dardisco <- function(df, v) cbind(df[1], sweep(df[-1], MARGIN=2, STATS=v, FUN="*"))
df2 <- cbind(data.frame(rep("a", 1000)), matrix(rnorm(100000), nrow=1000))
v2 <- rnorm(100)
all.equal(rscriven(df2, v2), josilber(df2, v2))
# [1] TRUE
all.equal(rscriven(df2, v2), dardisco(df2, v2))
# [1] TRUE

microbenchmark(rscriven(df2, v2), josilber(df2, v2), dardisco(df2, v2))
# Unit: milliseconds
#               expr       min        lq    median        uq        max neval
#  rscriven(df2, v2)  5.276458  5.378436  5.451041  5.587644   9.470207   100
#  josilber(df2, v2)  2.545144  2.753363  3.099589  3.704077   8.955193   100
#  dardisco(df2, v2) 11.647147 12.761184 14.196678 16.581004 132.428972   100
Run Code Online (Sandbox Code Playgroud)

感谢@thelatemail 指出,Map对于 100 倍大的数据帧,该方法要快得多:

df2 <- cbind(data.frame(rep("a", 10000)), matrix(rnorm(10000000), nrow=10000))
v2 <- rnorm(1000)
microbenchmark(rscriven(df2, v2), josilber(df2, v2), dardisco(df2, v2))
# Unit: milliseconds
#               expr       min         lq     median        uq       max neval
#  rscriven(df2, v2)  75.74051   90.20161   97.08931  115.7789  259.0855   100
#  josilber(df2, v2) 340.72774  388.17046  498.26836  514.5923  623.4020   100
#  dardisco(df2, v2) 928.81128 1041.34497 1156.39293 1271.4758 1506.0348   100
Run Code Online (Sandbox Code Playgroud)

似乎您需要进行基准测试以确定哪种方法对您的应用程序最快。

  • 这个结果对 df2 的大小非常敏感。尝试将其增加到 1000 列和 10000 行,结果将相反。 (2认同)