我正在尝试将数据框df
乘以向量v
,以便产品是数据框,i
行由{df[i,]*v
给出1}}。我可以这样做,例如,
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)
但仍然需要{_ 1}}等不可读的结构 我怎样才能在这里找到一个高效优雅的解决方法?
答案 0 :(得分:27)
这也有效:
data.frame(mapply(`*`,df,v))
在该解决方案中,您正在利用data.frame
是list
类型的事实,因此您可以迭代df
和v
的元素与mapply
同时进行。
不幸的是,您可以从mapply
输出的内容有限:简单list
或matrix
。如果您的数据量巨大,这可能会更有效:
data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE))
因为它会将其转换为list
,转换为data.frame
效率更高。
答案 1 :(得分:11)
如果您正在寻找速度和记忆效率 - 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
包中的data.table
函数对data.frame
进行就地修改:
for (i in seq_along(df))
set(df, j = i, value = df[[i]] * v[i])
这当然也适用于data.table
,如果列数很大,可能会明显加快。
答案 2 :(得分:8)
一种允许您将向量与矩阵组合在一起的语言必须在某些时候决定矩阵是行主要还是列主要有序。原因是:
> df * v
A B
1 0 4
2 4 0
3 0 8
4 8 0
5 0 12
是因为R首先按列操作。做双重转置技巧颠覆了这一点。很抱歉,如果这只是解释你所知道的,但我不知道另一种方法,除了明确地将v
扩展为相同大小的矩阵。
或者编写一个很好的函数,将非R风格的代码包装成R-Stylish。
答案 3 :(得分:3)
出了什么问题
t(apply(df, 1, function(x)x*v))
答案 4 :(得分:2)
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
答案 5 :(得分: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