#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)