26

我试图将一个数据框乘以df一个向量v,以便产品是一个数据框,其中i第 - 行由 给出df[i,]*v。我可以这样做,例如,通过

df <- data.frame(A=1:5, B=2:6); v <- c(0,2)
as.data.frame(t(t(df) * v))
   A  B
1  0  4
2  0  6
3  0  8
4  0 10
5  0 12

我确信必须有一种更R 风格的方法(而且是一种非常简单的方法!),但我什么都没有想到。我什至尝试过类似的东西

apply(df, MARGIN=1, function(x) x*v)

但是,仍然as.data.frame(t(.))需要像这样的不可读的结构。
我怎样才能在这里找到一个高效而优雅的解决方法?

4

6 回答 6

36

这也有效:

data.frame(mapply(`*`,df,v))

在该解决方案中,您利用的data.frame是 的类型这一事实,因此您可以同时list迭代 的df和的元素。vmapply

不幸的是,您可以输出的内容受到限制mapply:简单list,或matrix. 如果您的数据很大,这可能会更有效:

data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE))

因为它会将其转换为 a list,转换为 a 更有效data.frame

于 2013-08-22T14:27:50.630 回答
12

如果您正在寻找速度和内存效率 -data.table救援:

library(data.table)
dt = data.table(df)

for (i in seq_along(dt))
  dt[, (i) := dt[[i]] * v[i]]


eddi = function(dt) { for (i in seq_along(dt)) dt[, (i) := dt[[i]] * v[i]] }
arun = function(df) { df * matrix(v, ncol=ncol(df), nrow=nrow(df), byrow=TRUE) }
nograpes = function(df) { data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)) }

N = 1e6
dt = data.table(A = rnorm(N), B = rnorm(N))
v = c(0,2)

microbenchmark(eddi(copy(dt)), arun(copy(dt)), nograpes(copy(dt)), times = 10)
#Unit: milliseconds
#               expr       min        lq      mean    median        uq       max neval
#     eddi(copy(dt))  23.01106  24.31192  26.47132  24.50675  28.87794  34.28403    10
#     arun(copy(dt)) 337.79885 363.72081 450.93933 433.21176 516.56839 644.70103    10
# nograpes(copy(dt))  19.44873  24.30791  36.53445  26.00760  38.09078  95.41124    10

正如 Arun 在评论中指出的那样,也可以使用包中的set函数对'sdata.table进行这种就地修改:data.frame

for (i in seq_along(df))
  set(df, j = i, value = df[[i]] * v[i])

这当然也适用于data.table's,如果列数很大,可能会明显更快。

于 2013-08-22T16:37:13.047 回答
8

让您将向量与矩阵组合的语言必须在某个时候决定矩阵是按行优先还是按列优先排序。原因:

> df * v
  A  B
1 0  4
2 4  0
3 0  8
4 8  0
5 0 12

是因为 R 首先对列进行操作。使用双转置技巧颠覆了这一点。对不起,如果这只是解释你所知道的,但我不知道另一种方法,除了显式扩展v为相同大小的矩阵。

或者编写一个很好的函数,将不太 R 风格的代码包装成 R 风格的东西。

于 2013-08-22T14:22:02.683 回答
4

有什么问题

t(apply(df, 1, function(x)x*v))

?

于 2013-08-22T14:24:42.957 回答
3
library(purrr)

map2_dfc(df, v, `*`)

基准

N = 1e6
dt = data.table(A = rnorm(N), B = rnorm(N))
v = c(0,2)

eddi = function(dt) { for (i in seq_along(dt)) dt[, (i) := dt[[i]] * v[i]]; dt }
arun = function(df) { df * matrix(v, ncol=ncol(df), nrow=nrow(df), byrow=TRUE) }
nograpes = function(df) { data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)) }
ryan = function(df) {map2_dfc(df, v, `*`) }
library(microbenchmark)
microbenchmark(
  eddi(copy(dt))
  , arun(copy(dt))
  , nograpes(copy(dt))
  , ryan(copy(dt))
  , times = 100)


# Unit: milliseconds
# expr                     min        lq      mean    median        uq      max neval
# eddi(copy(dt))      8.367513  11.06719  24.26205  12.29132  19.35958 171.6212   100
# arun(copy(dt))     94.031272 123.79999 186.42155 148.87042 251.56241 364.2193   100
# nograpes(copy(dt))  7.910739  10.92815  27.68485  13.06058  21.39931 172.0798   100
# ryan(copy(dt))      8.154395  11.02683  29.40024  13.73845  21.77236 181.0375   100
于 2018-06-01T16:21:49.340 回答
1

我认为最快的方法(无需测试 data.table)是data.frame(t(t(df)*v)).

我的测试:

testit <- function(nrow, ncol)
{
    df <- as.data.frame(matrix(rnorm(nrow*ncol),nrow=nrow,ncol=ncol))

    v <- runif(ncol)

    r1 <- data.frame(t(t(df)*v))
    r2 <- data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE))
    r3 <- df * rep(v, each=nrow(df))

    stopifnot(identical(r1, r2) && identical(r1, r3))

    microbenchmark(data.frame(t(t(df)*v)), data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)), df * rep(v, each=nrow(df)))
}

结果

> set.seed(1)
> 
> testit(100,100)
Unit: milliseconds
                                             expr       min        lq    median        uq      max neval
                         data.frame(t(t(df) * v))  2.297075  2.359541  2.455778  3.804836 33.05806   100
 data.frame(mapply(`*`, df, v, SIMPLIFY = FALSE))  9.977436 10.401576 10.658964 11.762009 15.09721   100
                     df * rep(v, each = nrow(df)) 14.309822 14.956705 16.092469 16.516609 45.13450   100
> testit(1000,10)
Unit: microseconds
                                             expr      min       lq   median       uq      max neval
                         data.frame(t(t(df) * v))  754.844  805.062  844.431 1850.363 27955.79   100
 data.frame(mapply(`*`, df, v, SIMPLIFY = FALSE)) 1457.895 1497.088 1567.604 2550.090  4732.03   100
                     df * rep(v, each = nrow(df)) 5383.288 5527.817 5875.143 6628.586 32392.81   100
> testit(10,1000)
Unit: milliseconds
                                             expr       min        lq    median        uq       max neval
                         data.frame(t(t(df) * v))  17.07548  18.29418  19.91498  20.67944  57.62913   100
 data.frame(mapply(`*`, df, v, SIMPLIFY = FALSE))  99.90103 104.36028 108.28147 114.82012 150.05907   100
                     df * rep(v, each = nrow(df)) 112.21719 118.74359 122.51308 128.82863 164.57431   100
于 2013-08-22T17:01:32.130 回答