从r中矩阵的每一行中减去一个常数向量
Posted
技术标签:
【中文标题】从r中矩阵的每一行中减去一个常数向量【英文标题】:subtract a constant vector from each row in a matrix in r 【发布时间】:2021-08-13 04:39:37 【问题描述】:我有一个 5 列 4 行的矩阵。我也有一个 3 列的向量。我想在矩阵的每一行分别从第 3,4 和 5 列中减去向量中的值。
b <- matrix(rep(1:20), nrow=4, ncol=5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
c <- c(5,6,7)
得到
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 4 7 10
[2,] 2 6 5 8 11
[3,] 3 7 6 9 12
[4,] 4 8 7 10 13
【问题讨论】:
【参考方案1】:这正是 sweep
的用途:
b <- matrix(rep(1:20), nrow=4, ncol=5)
x <- c(5,6,7)
b[,3:5] <- sweep(b[,3:5], 2, x)
b
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 5 4 7 10
#[2,] 2 6 5 8 11
#[3,] 3 7 6 9 12
#[4,] 4 8 7 10 13
..甚至没有子集或重新分配:
sweep(b, 2, c(0,0,x))
【讨论】:
【参考方案2】:也许没有那么优雅,但是
b <- matrix(rep(1:20), nrow=4, ncol=5)
x <- c(5,6,7)
b[,3:5] <- t(t(b[,3:5])-x)
应该可以解决问题。我们对矩阵进行子集化以仅更改我们需要的部分,并使用t()
(转置)来翻转矩阵,因此简单的向量回收将负责从正确的行中减去。
如果你想避免转置,你可以这样做
b[,3:5] <- b[,3:5]-x[col(b[,3:5])]
也是。在这里,我们进行了两次子集化,并使用第二次为x
中的每个值获取正确的列,因为这两个矩阵将以相同的顺序索引。
我认为@thelatemail 链接的问题中我最喜欢的是
b[,3:5] <- sweep(b[,3:5], 2, x, `-`)
【讨论】:
遗憾的是,副本中最快的解决方案 (mat %*% diag(1/dev)
) 无法轻松转换为减法。 (mat %*% diag(1/dev) -1) %*% diag(dev)
比双转置既丑又慢:\【参考方案3】:
另一种方式,应用:
b[,3:5] <- t(apply(b[,3:5], 1, function(x) x-c))
【讨论】:
【参考方案4】:一个简单的解决方案:
b <- matrix(rep(1:20), nrow=4, ncol=5)
c <- c(5,6,7)
for(i in 1:nrow(b))
b[i,3:5] <- b[i,3:5] - c
【讨论】:
【参考方案5】:这可以通过rray
package 以非常令人满意的方式完成(使用其(类似numpy)广播-
运算符%b-%
):
#install.packages("rray")
library(rray)
b <- matrix(rep(1:20), nrow=4, ncol=5)
x <- c(5, 6, 7)
b[, 3:5] <- b[, 3:5] %b-% matrix(x, 1)
b
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 5 4 7 10
#> [2,] 2 6 5 8 11
#> [3,] 3 7 6 9 12
#> [4,] 4 8 7 10 13
对于大型矩阵,这甚至比sweep
更快:
#install.packages("bench")
res <- bench::press(
size = c(10, 1000, 10000),
frac_selected = c(0.1, 0.5, 1),
B <- matrix(sample(size*size), nrow=size, ncol=size)
B2 <- B
x <- sample(size, size=ceiling(size*frac_selected))
idx <- sample(size, size=ceiling(size*frac_selected))
bench::mark(rray = B2[, idx] <- B[, idx, drop = FALSE] %b-% matrix(x, nrow = 1); B2,
sweep = B2[, idx] <- sweep(B[, idx, drop = FALSE], MARGIN = 2, x); B2
)
)
plot(res)
【讨论】:
以上是关于从r中矩阵的每一行中减去一个常数向量的主要内容,如果未能解决你的问题,请参考以下文章