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

时间:2014-08-14 23:05:10

标签: r

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

e.g。数据框(df)包含以下列(col1, col2, col3, col4),向量(v)具有以下元素(v1,v2,v3)。

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

我一直在尝试df[c(2:4)] * c(v1,v2,v3),但似乎向量的元素并没有使每列的每一行都成倍增加。

4 个答案:

答案 0 :(得分:3)

您可以使用Map。这是一个例子

> ( df <- data.frame(a = letters[1:3], x = 1:3, y = 4:6, z = 7:9) )
#   a x y z
# 1 a 1 4 7
# 2 b 2 5 8
# 3 c 3 6 9    
> v <- c(5, 10, 15)
> cbind(df[1], Map(`*`, df[-1], v))
#   a  x  y   z
# 1 a  5 40 105
# 2 b 10 50 120
# 3 c 15 60 135

在此示例中,

  • x乘以v[1](5)
  • y乘以v[2](10)
  • z乘以v[3](15)
  • cbind用于将未使用的列a附加到我们操作的列

答案 1 :(得分:3)

您可以尝试(使用Richard Scriven的答案中的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

将矩阵乘以向量时,它会按列相乘。由于您希望将行乘以向量,因此我们使用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

感谢@thelatemail指出{100}大数据框的Map方法速度更快:

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

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

答案 2 :(得分:2)

不是那么快,但更灵活:

sweep(df[-1], MARGIN=2, STATS=v, FUN="*")

答案 3 :(得分:1)

简单&#39;申请&#39;函数也可以在这里使用,按行读取:

df[-1]= (t(apply(df[-1],1, FUN=function(x)x*v)))
df
  a  x  y   z
1 a  5 40 105
2 b 10 50 120
3 c 15 60 135