按列滚动总和产品

时间:2016-09-27 20:13:55

标签: r matrix rcpp

我有两个矩阵,我想将它们相乘,这样得到的矩阵的每个值都是前两个矩阵中相同列的滚动总和。

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套餐但无法得到正确的答案。解决方案越快越好,因为这是需要多次迭代的优化的一部分。

3 个答案:

答案 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)