在 R 中,如何用向量的元素划分矩阵的每一行

我想把矩阵的每个 划船除以一个固定的向量。例如

mat<-matrix(1,ncol=2,nrow=2,TRUE)
dev<-c(5,10)

mat/dev每个 专栏除以 dev

     [,1] [,2]
[1,]  0.2  0.2
[2,]  0.1  0.1

但是,我希望得到这样的结果,即执行 就行而言操作:

rbind(mat[1,]/dev, mat[2,]/dev)


[,1] [,2]
[1,]  0.2  0.1
[2,]  0.2  0.1

有明确的命令要去那里吗?

87615 次浏览

你要找的是应用在行上的 apply函数:

t(apply(mat, 1, function(x) x/dev))

下面是一些增加代码长度的方法:

t(t(mat) / dev)


mat / dev[col(mat)] #  @DavidArenburg & @akrun


mat %*% diag(1 / dev)


sweep(mat, 2, dev, "/")


t(apply(mat, 1, "/", dev))


plyr::aaply(mat, 1, "/", dev)


mat / rep(dev, each = nrow(mat))


mat / t(replace(t(mat), TRUE, dev))


mapply("/", as.data.frame(mat), dev)  # added later


mat / matrix(dev, nrow(mat), ncol(mat), byrow = TRUE)  # added later


do.call(rbind, lapply(as.data.frame(t(mat)), "/", dev))


mat2 <- mat; for(i in seq_len(nrow(mat2))) mat2[i, ] <- mat2[i, ] / dev

数据框架

如果 mat是一个数据帧并产生一个数据帧结果,那么以 mat /开头的所有解决方案也都可以工作。sweep解决方案和最后一个解决方案(即 mat2)的情况也是如此。mapply解决方案使用 data.frame,但生成一个矩阵。

矢量

如果 mat是一个普通向量而不是一个矩阵,那么它们中的任何一个都会返回一列矩阵

t(t(mat) / dev)
mat / t(replace(t(mat), TRUE, dev))

这个返回一个向量:

plyr::aaply(mat, 1, "/", dev)

其他人给出一个错误,警告或不理想的答案。

基准

代码的简洁和清晰可能比速度更重要,但为了完整起见,这里有一些使用10次重复和100次重复的基准测试。

library(microbenchmark)
library(plyr)


set.seed(84789)


mat<-matrix(runif(1e6),nrow=1e5)
dev<-runif(10)


microbenchmark(times=10L,
"1" = t(t(mat) / dev),
"2" = mat %*% diag(1/dev),
"3" = sweep(mat, 2, dev, "/"),
"4" = t(apply(mat, 1, "/", dev)),
"5" = mat / rep(dev, each = nrow(mat)),
"6" = mat / t(replace(t(mat), TRUE, dev)),
"7" = aaply(mat, 1, "/", dev),
"8" = do.call(rbind, lapply(as.data.frame(t(mat)), "/", dev)),
"9" = {mat2 <- mat; for(i in seq_len(nrow(mat2))) mat2[i, ] <- mat2[i, ] / dev},
"10" = mat/dev[col(mat)])

给予:

Unit: milliseconds
expr         min          lq       mean      median          uq        max neval
1    7.957253    8.136799   44.13317    8.370418    8.597972  366.24246    10
2    4.678240    4.693771   10.11320    4.708153    4.720309   58.79537    10
3   15.594488   15.691104   16.38740   15.843637   16.559956   19.98246    10
4   96.616547  104.743737  124.94650  117.272493  134.852009  177.96882    10
5   17.631848   17.654821   18.98646   18.295586   20.120382   21.30338    10
6   19.097557   19.365944   27.78814   20.126037   43.322090   48.76881    10
7 8279.428898 8496.131747 8631.02530 8644.798642 8741.748155 9194.66980    10
8  509.528218  524.251103  570.81573  545.627522  568.929481  821.17562    10
9  161.240680  177.282664  188.30452  186.235811  193.250346  242.45495    10
10    7.713448    7.815545   11.86550    7.965811    8.807754   45.87518    10

对所有重复100次、持续时间 < 20毫秒的人重新进行测试:

microbenchmark(times=100L,
"1" = t(t(mat) / dev),
"2" = mat %*% diag(1/dev),
"3" = sweep(mat, 2, dev, "/"),
"5" = mat / rep(dev, each = nrow(mat)),
"6" = mat / t(replace(t(mat), TRUE, dev)),
"10" = mat/dev[col(mat)])

给予:

Unit: milliseconds
expr       min        lq      mean    median        uq       max neval
1  8.010749  8.188459 13.972445  8.560578 10.197650 299.80328   100
2  4.672902  4.734321  5.802965  4.769501  4.985402  20.89999   100
3 15.224121 15.428518 18.707554 15.836116 17.064866  42.54882   100
5 17.625347 17.678850 21.464804 17.847698 18.209404 303.27342   100
6 19.158946 19.361413 22.907115 19.772479 21.142961  38.77585   100
10  7.754911  7.939305  9.971388  8.010871  8.324860  25.65829   100

所以在这两个测试 # 2(使用 diag)中都是最快的。原因可能在于其几乎直接呼吁 BLAS,而 # 1依赖于昂贵的 t

不仅比最快的基本方法(使用矩阵乘法,参见 @ G. Grothendieck 的回答)更快,而且更易读的是使用 rray包裹,它允许数字式广播与它的 %b/%操作员一起进行除法:

mat %b/% matrix(dev, nrow = 1)

#install.packages("rray")
library(rray)


set.seed(84789)
mat <- matrix(runif(1e6), nrow = 1e5)
dev <- runif(10)


bench::mark(rray = {ret <- mat %b/% matrix(dev, nrow = 1); attr(ret, "dimnames") <- NULL; ret},
matmult = mat %*% diag(1/dev)
)
#> # A tibble: 2 x 6
#>   expression      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 rray         8.24ms   8.82ms     108.     7.67MB     46.4
#> 2 matmult     11.17ms  12.01ms      77.6    7.66MB     13.9