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

e5njpo68  于 2023-05-26  发布在  其他
关注(0)|答案(7)|浏览(391)

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

flvtvl501#

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

rjzwgtxy2#

也许不是那么优雅,但是

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

l5tcr1uw3#

另一种方法,使用apply:

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

gab6jxml4#

一个简单的解决方案:

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
}
kxeu7u2r

kxeu7u2r5#

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

odopli94

odopli946#

出于性能考虑,{collapse}包中的运算符%r-%是最好的。请参见以下基准:

# the original question:
b <- matrix(rep(1:20), nrow=4, ncol=5)
c <- c(5,6,7)
box::use(collapse[`%r-%`], rray[`%b-%`])
bench::mark(
  collapse = b[, 3:5] %r-% c,
  transpose = t(t(b[, 3:5]) - c),
  sweep = sweep(b[, 3:5], 2, c),
  rray = b[, 3:5] %b-% matrix(c, nrow = 1),
  check = F
)
#> # A tibble: 4 × 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 collapse      5.2µs    5.8µs   145873.        0B    14.6 
#> 2 transpose     7.9µs    8.7µs    97164.        0B     9.72
#> 3 sweep        26.6µs   29.4µs    28480.    50.6KB    19.9 
#> 4 rray         85.5µs   91.7µs     9262.   184.7KB    14.9

# further testing for larger data
data <- matrix(rnorm(100*1000), nrow = 100)
bench::press(
  ncol = c(10, 100, 1000), {
    b <- data[, 1:ncol]
    c <- rnorm(ncol)
    bench::mark(
      collapse = b %r-% c,
      transpose = t(t(b) - c),
      sweep = sweep(b, 2, c),
      rray = b %b-% matrix(c, nrow = 1),
      check = F
    )
  }
)
#> Running with:
#>    ncol
#> 1    10
#> 2   100
#> 3  1000
#> # A tibble: 12 × 7
#>    expression  ncol      min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr> <dbl> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 collapse      10    5.3µs    7.3µs    84959.    7.86KB     8.50
#>  2 transpose     10   11.6µs   15.2µs    49990.   15.72KB    20.0 
#>  3 sweep         10   29.9µs     33µs    24897.   15.72KB    17.4 
#>  4 rray          10   56.6µs   66.1µs    13142.    9.94KB    12.7 
#>  5 collapse     100   12.6µs   49.1µs    17810.   78.17KB    29.5 
#>  6 transpose    100     49µs  119.3µs     7639.  156.34KB    26.1 
#>  7 sweep        100   72.9µs  153.8µs     5882.  156.34KB    18.2 
#>  8 rray         100   92.3µs  129.2µs     6690.      79KB    13.2 
#>  9 collapse    1000     78µs  441.8µs     2023.   781.3KB    36.1 
#> 10 transpose   1000  689.2µs   1.11ms      824.    1.53MB    28.9 
#> 11 sweep       1000  459.8µs   1.18ms      748.    1.53MB    29.9 
#> 12 rray        1000  402.2µs  758.4µs     1212.  789.16KB    25.9

创建于2023-05-22使用reprex v2.0.2
虽然对于较大的矩阵,{rray} %b-%可能比sweep更快,但{collapse} %r-%优于所有其他方法。

dojqjjoe

dojqjjoe7#

我们可以使用outer来创建掩码矩阵msk,然后从b中减去它,例如,

> x <- c(5, 6, 7)

> (msk <- outer(rep(1, nrow(b)), replace(rep(0, ncol(b)), c(3, 4, 5), x)))
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    5    6    7
[2,]    0    0    5    6    7
[3,]    0    0    5    6    7
[4,]    0    0    5    6    7

> (b <- b - msk)
     [,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

相关问题