R - 将 df 或矩阵的每一行与一个向量相乘
R - Multiply every row of df or matrix with a vector
我无法完成这项工作,尽管它看起来相当简单。
我想将矩阵(或数据框或数据表)b 中的每一行与向量 a 相乘。
a <- data.table(t(1:4))
b <- matrix(data=2, nrow=3, ncol=4)
期望的输出(矩阵、数据框或数据表形式):
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
任何人都可以帮助我如何(有效地)做到这一点吗?
选项#1: 使用 data.table
功能:
注意:之所以有效,是因为列号和值与 a
匹配
a[,lapply(.SD,function(x)(x*b[,x]))]
# V1 V2 V3 V4
#1: 2 4 6 8
#2: 2 4 6 8
#3: 2 4 6 8
选项#2: 可以是:
t(t(b) * (as.matrix(a)[1,]))
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
更新
选项#3: 处理 a
中的 decimal/actual 值
#Cases when `a` contains decimal values can be handled as
a <- data.table(t(c(1, 0.24, 3, 4)))
b <- matrix(data=2, nrow=3, ncol=4)
a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))]
# V1 V2 V3 V4
#1: 2 0.48 6 8
#2: 2 0.48 6 8
#3: 2 0.48 6 8
dplyr::bind_rows(apply(b, 1, `*`, a))
V1 V2 V3 V4
1: 2 4 6 8
2: 2 4 6 8
3: 2 4 6 8
棘手的部分是您的 a
是 data.table。如果真的是vector,那就简单多了:
apply(b, 1, `*`, 1:4)
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 4 4 4
[3,] 6 6 6
[4,] 8 8 8
在我这边,我会使用 R 的 built-in 方法进行矩阵乘法 %*%
。
考虑到 向量:[注意:data.table
不是 vector
]
a <- c(1:4)
并考虑矩阵:
b <- matrix(data=2, nrow=3, ncol=4)
您的输出为:
output <- b %*% diag(a)
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
如果您认为此解决方案无法满足您的需求,那么我建议使用 built-in 函数 sweep
:
sweep(b, 2, a, FUN = "*")
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
b*rep(unlist(a),each=nrow(b))
# [,1] [,2] [,3] [,4]
# [1,] 2 4 6 8
# [2,] 2 4 6 8
# [3,] 2 4 6 8
或者只是 b*rep(a,each=nrow(b))
如果你定义 a <- 1:4
这只是一个向量化的元素明智的乘法,没有来自 rep
的转换应用程序。
编辑:
似乎是 rep 拖慢了我的解决方案。这是一个基准测试,其中我包含一个带有预计算代表的选项,以及对扫描选项的一些改进(仅从源代码中获取相关部分)。
a <- data.table(t(1:200))
b <- matrix(data=2, nrow=100000, ncol=200)
a_vec <- unlist(a)
rep_a <- rep(a_vec,each=nrow(b))
microbenchmark::microbenchmark(
mkr1 = a[,lapply(.SD,function(x)(x*b[,x]))],
mkr2 = t(t(b) * (as.matrix(a)[1,])),
mkr_update = a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))],
mm = b*rep(unlist(a),each=nrow(b)),
mm_cheat = b*rep_a,
regular_sweep = sweep(b,2,unlist(a),`*`),
regular_sweep2 = sweep(b,2,a_vec,`*`),
improved_sweepA1 = b*aperm(array(unlist(a),rev(dim(b)))),
improved_sweepA2 = b*aperm(array(a_vec,rev(dim(b)))),
improved_sweepB1 = b*a[rep_len(1,nrow(b)),],
improved_sweepB2 = b*t(a_vec)[rep_len(1,nrow(b)),],
unit = "relative",
times=50)
Unit: relative
expr min lq mean median uq max neval
mkr1 42.12228 44.15266 50.23959 46.35240 57.20280 65.07289 50
mkr2 114.58427 124.19653 125.25660 131.08677 124.17058 114.91137 50
mkr_update 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000 50
mm 231.34331 223.74365 217.50145 225.91117 215.90765 165.64814 50
mm_cheat 13.38838 13.22556 14.94682 13.36649 12.95260 25.15564 50
regular_sweep 96.15758 124.26746 121.04428 128.67282 129.19407 119.20210 50
regular_sweep2 97.79001 124.69191 124.74650 134.64249 134.97407 107.47152 50
improved_sweepA1 96.57837 124.86189 116.93736 127.08909 124.92805 105.83318 50
improved_sweepA2 96.27737 122.49773 118.45262 128.13369 126.15029 106.58669 50
improved_sweepB1 214.95773 227.39523 226.04339 248.38553 232.50401 161.45341 50
improved_sweepB2 31.20967 32.61873 37.74552 33.70969 41.52149 55.93362 50
感谢您的回复。我已经在速度上测试了上面建议的解决方案(使用我的向量和矩阵的实际大小)以使用最有效的解决方案:
a <- data.table(t(1:200))
b <- matrix(data=2, nrow=100000, ncol=200)
system.time(sweep(b, MARGIN=2, t(a), "*"))
# user system elapsed
# 0.31 0.06 0.39
system.time(a[,lapply(.SD,function(x)(x*b[,x]))])
# user system elapsed
# 0.2 0.0 0.2
#system.time(bind_rows(apply(b,1,`*`,a)))
#took 100+ so stopped it manually
system.time(t(t(b)*(as.matrix(a)[1,])))
# user system elapsed
# 0.31 0.05 0.36
system.time(apply(b, 1, `*`, 1:200))
# user system elapsed
# 1.20 0.11 1.31
system.time(b*rep(unlist(a),each=nrow(b)))
# user system elapsed
# 0.83 0.05 0.89
system.time(b*rep((1:200),each=nrow(b)))
# user system elapsed
# 0.36 0.06 0.42
我无法完成这项工作,尽管它看起来相当简单。 我想将矩阵(或数据框或数据表)b 中的每一行与向量 a 相乘。
a <- data.table(t(1:4))
b <- matrix(data=2, nrow=3, ncol=4)
期望的输出(矩阵、数据框或数据表形式):
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
任何人都可以帮助我如何(有效地)做到这一点吗?
选项#1: 使用 data.table
功能:
注意:之所以有效,是因为列号和值与 a
a[,lapply(.SD,function(x)(x*b[,x]))]
# V1 V2 V3 V4
#1: 2 4 6 8
#2: 2 4 6 8
#3: 2 4 6 8
选项#2: 可以是:
t(t(b) * (as.matrix(a)[1,]))
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
更新
选项#3: 处理 a
#Cases when `a` contains decimal values can be handled as
a <- data.table(t(c(1, 0.24, 3, 4)))
b <- matrix(data=2, nrow=3, ncol=4)
a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))]
# V1 V2 V3 V4
#1: 2 0.48 6 8
#2: 2 0.48 6 8
#3: 2 0.48 6 8
dplyr::bind_rows(apply(b, 1, `*`, a))
V1 V2 V3 V4
1: 2 4 6 8
2: 2 4 6 8
3: 2 4 6 8
棘手的部分是您的 a
是 data.table。如果真的是vector,那就简单多了:
apply(b, 1, `*`, 1:4)
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 4 4 4
[3,] 6 6 6
[4,] 8 8 8
在我这边,我会使用 R 的 built-in 方法进行矩阵乘法 %*%
。
考虑到 向量:[注意:data.table
不是 vector
]
a <- c(1:4)
并考虑矩阵:
b <- matrix(data=2, nrow=3, ncol=4)
您的输出为:
output <- b %*% diag(a)
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
如果您认为此解决方案无法满足您的需求,那么我建议使用 built-in 函数 sweep
:
sweep(b, 2, a, FUN = "*")
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 2 4 6 8
[3,] 2 4 6 8
b*rep(unlist(a),each=nrow(b))
# [,1] [,2] [,3] [,4]
# [1,] 2 4 6 8
# [2,] 2 4 6 8
# [3,] 2 4 6 8
或者只是 b*rep(a,each=nrow(b))
如果你定义 a <- 1:4
这只是一个向量化的元素明智的乘法,没有来自 rep
的转换应用程序。
编辑:
似乎是 rep 拖慢了我的解决方案。这是一个基准测试,其中我包含一个带有预计算代表的选项,以及对扫描选项的一些改进(仅从源代码中获取相关部分)。
a <- data.table(t(1:200))
b <- matrix(data=2, nrow=100000, ncol=200)
a_vec <- unlist(a)
rep_a <- rep(a_vec,each=nrow(b))
microbenchmark::microbenchmark(
mkr1 = a[,lapply(.SD,function(x)(x*b[,x]))],
mkr2 = t(t(b) * (as.matrix(a)[1,])),
mkr_update = a[,lapply(V1:V4,function(i)(a[[i]]*b[,i]))],
mm = b*rep(unlist(a),each=nrow(b)),
mm_cheat = b*rep_a,
regular_sweep = sweep(b,2,unlist(a),`*`),
regular_sweep2 = sweep(b,2,a_vec,`*`),
improved_sweepA1 = b*aperm(array(unlist(a),rev(dim(b)))),
improved_sweepA2 = b*aperm(array(a_vec,rev(dim(b)))),
improved_sweepB1 = b*a[rep_len(1,nrow(b)),],
improved_sweepB2 = b*t(a_vec)[rep_len(1,nrow(b)),],
unit = "relative",
times=50)
Unit: relative
expr min lq mean median uq max neval
mkr1 42.12228 44.15266 50.23959 46.35240 57.20280 65.07289 50
mkr2 114.58427 124.19653 125.25660 131.08677 124.17058 114.91137 50
mkr_update 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000 50
mm 231.34331 223.74365 217.50145 225.91117 215.90765 165.64814 50
mm_cheat 13.38838 13.22556 14.94682 13.36649 12.95260 25.15564 50
regular_sweep 96.15758 124.26746 121.04428 128.67282 129.19407 119.20210 50
regular_sweep2 97.79001 124.69191 124.74650 134.64249 134.97407 107.47152 50
improved_sweepA1 96.57837 124.86189 116.93736 127.08909 124.92805 105.83318 50
improved_sweepA2 96.27737 122.49773 118.45262 128.13369 126.15029 106.58669 50
improved_sweepB1 214.95773 227.39523 226.04339 248.38553 232.50401 161.45341 50
improved_sweepB2 31.20967 32.61873 37.74552 33.70969 41.52149 55.93362 50
感谢您的回复。我已经在速度上测试了上面建议的解决方案(使用我的向量和矩阵的实际大小)以使用最有效的解决方案:
a <- data.table(t(1:200))
b <- matrix(data=2, nrow=100000, ncol=200)
system.time(sweep(b, MARGIN=2, t(a), "*"))
# user system elapsed
# 0.31 0.06 0.39
system.time(a[,lapply(.SD,function(x)(x*b[,x]))])
# user system elapsed
# 0.2 0.0 0.2
#system.time(bind_rows(apply(b,1,`*`,a)))
#took 100+ so stopped it manually
system.time(t(t(b)*(as.matrix(a)[1,])))
# user system elapsed
# 0.31 0.05 0.36
system.time(apply(b, 1, `*`, 1:200))
# user system elapsed
# 1.20 0.11 1.31
system.time(b*rep(unlist(a),each=nrow(b)))
# user system elapsed
# 0.83 0.05 0.89
system.time(b*rep((1:200),each=nrow(b)))
# user system elapsed
# 0.36 0.06 0.42