вычтите постоянный вектор из каждой строки матрицы в r

#r #vector #matrix

#r #вектор #матрица

Вопрос:

У меня есть матрица с 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() (transpose), чтобы перевернуть матрицу, поэтому простая переработка вектора позаботится о вычитании из правильной строки.

Если вы хотите избежать транспонирования, вы могли бы сделать что-то вроде

 b[,3:5] <- b[,3:5]-x[col(b[,3:5])]
  

также. Здесь мы подмножествуем дважды, и мы используем второй, чтобы получить правильный столбец для каждого значения в x , потому что обе эти матрицы будут индексироваться в одном и том же порядке.

Я думаю, что мой любимый вопрос, связанный с @thelatemail, был

 b[,3:5] <- sweep(b[,3:5], 2, x, `-`)
  

Комментарии:

1. жаль, что самое быстрое решение в дубликате ( mat %*% diag(1/dev) ) не может быть легко переведено в вычитание. (mat %*% diag(1/dev) -1) %*% diag(dev) одновременно уродливо и медленнее, чем двойное транспонирование :

Ответ №3:

Другой способ, с помощью apply:

 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 пакета очень удобным способом (используя его (подобный 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)
  

результаты тестирования