我有两个矩阵,我想将它们相乘,这样得到的矩阵的每个值都是前两个矩阵中相同列的滚动总和。
x<-matrix(seq(1:30), ncol=3)
x
[,1] [,2] [,3]
[1,] 1 11 21
[2,] 2 12 22
[3,] 3 13 23
[4,] 4 14 24
[5,] 5 15 25
[6,] 6 16 26
[7,] 7 17 27
[8,] 8 18 28
[9,] 9 19 29
[10,] 10 20 30
y<-matrix(rep(seq(1:3), 4), ncol=3)/10
y
[,1] [,2] [,3]
[1,] 0.1 0.2 0.3
[2,] 0.2 0.3 0.1
[3,] 0.3 0.1 0.2
[4,] 0.1 0.2 0.3
所以结果如下:
1.8 9.9 20.3
2.5 10.7 21.2
3.2 11.5 22.1
3.9 12.3 23
4.6 13.1 23.9
5.3 13.9 24.8
6 14.7 25.7
在上面的示例输出中,10.7
的值计算为:
output[2, 2] = 12 * 0.2 + 13 * 0.3 + 14 * 0.1 + 15 * 0.2
有人知道怎么做吗?我一直在玩RcppRoll
套餐但无法得到正确的答案。解决方案越快越好,因为这是需要多次迭代的优化的一部分。
答案 0 :(得分:5)
使用colSums:
t(
sapply(1:(nrow(x) - nrow(y) + 1), function(i){
colSums(x[i:((nrow(y)) + i - 1), ] * y)
})
)
基于更大的示例数据(在ZheyuanLi的答案中提供),microbenchmark:
Unit: milliseconds
expr min lq mean median uq max neval cld
zx 179.8928 186.8033 202.5204 192.3973 199.7500 299.5910 100 a
ZL 365.9814 368.3878 391.8303 370.0935 373.4502 489.5045 100 b
答案 1 :(得分:4)
您正在寻找 convolution 。在R中,函数convolve
通过FFT(快速傅里叶变换)计算两个向量的卷积。阅读?convolve
。请注意,我们特别需要type = "filter"
。
例如,x[,1]
和y[,1]
的卷积为:
convolve(x[,1], y[,1], type = "filter")
# [1] 1.8 2.5 3.2 3.9 4.6 5.3 6.0
使用sapply
包装起来很简单:
sapply(seq_len(ncol(x)), function (i) convolve(x[,i], y[,i], type = "filter"))
# [,1] [,2] [,3]
#[1,] 1.8 9.9 20.3
#[2,] 2.5 10.7 21.2
#[3,] 3.2 11.5 22.1
#[4,] 3.9 12.3 23.0
#[5,] 4.6 13.1 23.9
#[6,] 5.3 13.9 24.8
#[7,] 6.0 14.7 25.7
我认为在您的上下文中,您的矩阵x
是一个很薄的矩阵,即它的行数多于列数。我的sapply
位于专栏中。为什么不进行实际测试并做一些分析?
x <- matrix(rnorm(3000 * 100), 3000) ## `3000 * 100` matrix
y <- matrix(rnorm(100 * 100), 100) ## `100 * 100` matrix
Rprof("foo.out")
sapply(seq_len(ncol(x)), function (i) convolve(x[,i], y[,i], type = "filter"))
Rprof(NULL)
summaryRprof("foo.out")$by.total
total.time total.pct self.time self.pct
"sapply" 1.32 100.00 0.00 0.00
"FUN" 1.30 98.48 0.02 1.52
"lapply" 1.30 98.48 0.00 0.00
"convolve" 1.28 96.97 0.08 6.06
"fft" 1.12 84.85 1.12 84.85
"rep.int" 0.04 3.03 0.04 3.03
"array" 0.02 1.52 0.02 1.52
"c" 0.02 1.52 0.02 1.52
"Re" 0.02 1.52 0.02 1.52
"simplify2array" 0.02 1.52 0.00 0.00
96%+
的时间花费在convolve
上,因此sapply
的开销可以忽略不计。
答案 2 :(得分:4)
这可以通过rollapply
在一行中完成。它使用整个对象方法,即没有明确的下标。
library(zoo)
rollapply(x, nrow(y), function(x) colSums(x*y), by.column = FALSE)
,并提供:
[,1] [,2] [,3]
[1,] 1.8 9.9 20.3
[2,] 2.5 10.7 21.2
[3,] 3.2 11.5 22.1
[4,] 3.9 12.3 23.0
[5,] 4.6 13.1 23.9
[6,] 5.3 13.9 24.8
[7,] 6.0 14.7 25.7
注意:虽然不是更短,但使用magrittr这可以替代写成:
library(magrittr)
library(zoo)
x %>% rollapply(nrow(y), . %>% `*`(y) %>% colSums, by.column = FALSE)