从r中的矩阵中的每一行中减去一个常量向量

时间:2014-07-01 23:31:02

标签: r vector matrix

我有一个包含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

5 个答案:

答案 0 :(得分:44)

这正是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))

答案 1 :(得分:6)

也许不那么优雅,但

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, `-`)

答案 2 :(得分:2)

一个简单的解决方案:

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
}

答案 3 :(得分:2)

另一种方式,使用apply:

b[,3:5] <- t(apply(b[,3:5], 1, function(x) x-c))

答案 4 :(得分:1)

这可以通过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)

benchmark results