我有一个n x m矩阵mat
和一个长度为m的向量vec
。有没有一种快速的方法从矩阵的每一行中减去这个向量,并根据需要进行回收。
示例:
mat = structure(c(3.01, 1.44, 3.31, 1.34, 3.79, 1.65, 3.06, 1.12, 2.34,
0.27, 2.63, 0.63, 2.73, 0.94, 3.1, 1.34, 2.75, 0.75, 2.83, 0.58
), .Dim = c(2L, 10L))
vec = colMeans(mat)
从vec
的每一行中减去mat
的最快方法是什么? aperm
似乎非常低效。
aperm(aperm(mat) - vec)
分配第二个矩阵也不是太漂亮了。
mat - matrix(vec, ncol=ncol(mat), nrow = nrow(mat), by.row =T)
注意:此问题是前一个问题的重新过帐,作为重复结束。不幸的是,重复项缺乏相关的,彻底的答案,因此我决定将其与答案一起添加。
答案 0 :(得分:3)
library(microbenchmark)
byrow.speed.benchmark = function(ncol, nrow) {
mat = matrix(rnorm(nrow * ncol), nrow = nrow, ncol = ncol)
vec = colSums(mat)
microbenchmark(
aperm(aperm(mat) - vec),
t(t(mat) - vec),
mat - matrix(vec, ncol=ncol(mat), nrow = nrow(mat), byrow =T),
sweep(mat, 2, vec),
mat - rep(vec, each = nrow(mat)),
#mat %*% diag(vec),
mat - vec[col(mat)],
mat - vec,
times = 300
)
}
byrow.speed.benchmark(10, 10)
比较几种跨矩阵行应用的方法,我们发现分配矢量是最快的。
Unit: nanoseconds
expr min lq mean median uq max neval
aperm(aperm(mat) - vec) 8642 9283 10214.287 9923 10243 80344 300
t(t(mat) - vec) 6722 7362 7950.130 8002 8323 27208 300
mat - matrix(vec, ncol = ncol(mat), nrow = nrow(mat), byrow = T) 3201 3841 4282.947 4161 4482 20486 300
sweep(mat, 2, vec) 26888 28489 30016.310 29448 30089 85145 300
mat - rep(vec, each = nrow(mat)) 2560 3201 3481.630 3521 3841 10883 300
mat - vec[col(mat)] 1600 2241 2594.970 2561 2881 6081 300
mat - vec 0 320 389.530 320 321 1921 300
这如何缩放?
ncols = floor(10^((4:12)/4))
nrows = floor(10^((4:12)/4))
results = cbind(expand.grid(ncols, nrows), aperm = NA, t=NA, alloc = NA, sweep = NA, rep = NA, indices=NA, control = NA)
for (i in seq(nrow(results))) {
df = byrow.speed.benchmark(results[i,1], results[i,2])
results[i,3:9] = sapply(split(df$time, as.numeric(df$expr)), mean)
}
library(ggplot2)
df = reshape2::melt(results, id.vars= c("Var1", "Var2"))
colnames(df) = c("ncol", "nrow", "method", "meantime")
ggplot(subset(df, ncol==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method)) + ggtitle("Scaling with cell number.") + coord_cartesian(ylim = c(0, 1E6))
ggplot(subset(df, ncol==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method)) + ggtitle("Scaling with cell number.") #+ coord_cartesian(ylim = c(0, 5E7))
ggplot(subset(df, ncol==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method)) + coord_cartesian(ylim = c(0, 3E7)) + ggtitle("Scaling with a wide matrix (1000 columns)")
ggplot(subset(df, nrow==1000)) + geom_point(aes(x = log10(ncol*nrow), y=meantime, colour = method))+ geom_line(aes(x = log10(ncol*nrow), y=meantime, colour = method)) + coord_cartesian(ylim = c(0, 3E7)) + ggtitle("Scaling with a tall matrix (1000 rows)")
粉色线是我们将矢量应用于内置回收的列的情况。使用matrix(vec, byrow=T)
分配矩阵可以最大限度地扩展我们的选项。
关于矩阵尺寸对此影响的可能性是对于宽矩阵和高矩阵的缩放。
编辑:值得注意的是(正如预期的那样)矩阵分配不像矢量回收那样扩展。在这方面,上述情节略有误导。