如何在 Rcpp 中对矩阵的 10 步行求和?

How to sum 10 step rows of matrix in Rcpp?

我想使用 Rcpp 获得以下结果。 当大数据时,R 很慢。 因此,我尝试在 Rcpp 中编码。

x <- matrix(1:150, ncol = 5)
z <- matrix(nrow = nrow(x) / 10, ncol = 5)
for (i in 1:5) {
    for (j in 1:(nrow(x) / 10)) {
    k = (j - 1) * 10 + 1;
    z[j, i] <- sum(x[k:(k+9), i])
    }
}
x
       [,1] [,2] [,3] [,4] [,5]
 [1,]    1   31   61   91  121
 [2,]    2   32   62   92  122
 [3,]    3   33   63   93  123
 [4,]    4   34   64   94  124
 [5,]    5   35   65   95  125
 [6,]    6   36   66   96  126
 [7,]    7   37   67   97  127
 [8,]    8   38   68   98  128
 [9,]    9   39   69   99  129
[10,]   10   40   70  100  130
[11,]   11   41   71  101  131
[12,]   12   42   72  102  132
[13,]   13   43   73  103  133
[14,]   14   44   74  104  134
[15,]   15   45   75  105  135
[16,]   16   46   76  106  136
[17,]   17   47   77  107  137
[18,]   18   48   78  108  138
[19,]   19   49   79  109  139
[20,]   20   50   80  110  140
[21,]   21   51   81  111  141
[22,]   22   52   82  112  142
[23,]   23   53   83  113  143
[24,]   24   54   84  114  144
[25,]   25   55   85  115  145
[26,]   26   56   86  116  146
[27,]   27   57   87  117  147
[28,]   28   58   88  118  148
[29,]   29   59   89  119  149
[30,]   30   60   90  120  150

z
      [,1] [,2] [,3] [,4] [,5]
 [1,]   55  355  655  955 1255
 [2,]  155  455  755 1055 1355
 [3,]  255  555  855 1155 1455

我试过的代码Rcpp如下

#include <Rcpp.h> 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector mySum(NumericMatrix x) {

    int ncol = x.ncol();
    int nrow = x.nrow();
    int outRow = nrow / 10;
    int i;
    int j;
    int k;
    Rcpp::NumericMatrix z(outRow, ncol);

    for (i = 0; i < ncol; i++) {
        for (j = 0; j < outRow; j++) {
        k = j * 10;
        Rcpp::SubMatrix<REALSXP> sm = x(Range(k, k + 9), i);
        Rcpp::NumericMatrix m(sm);
        double s = Rcpp::sum(m);
        z(j, i) = s;
        }
    }
  return z;
}

但是,由于错误,它没有移动。 请告诉我解决方案。

test.cpp: In function 'Rcpp::NumericVector mySum(Rcpp::NumericMatrix)':
test.cpp:18:59: error: no match for call to '(Rcpp::NumericMatrix {aka Rcpp::Matrix<14>}) (Rcpp::Range, int&)'

在处理矩阵时我更喜欢使用 RcppArmadillo,原因之一是文档非常好 (http://arma.sourceforge.net/docs.html#accu)。我稍微重写了你的代码,似乎工作正常:

library(RcppArmadillo)
library(Rcpp)

cppFunction("
NumericMatrix mySum(arma::mat x) {

    int ncol = x.n_cols;
    int nrow = x.n_rows;
    int outRow = nrow / 10;
    int i, j, k;
    NumericMatrix z(outRow, ncol);

    for (i = 0; i < ncol; i++) {
        for (j = 0; j < outRow; j++) {
            k = j * 10;
            arma::mat sm = x(arma::span(k, k+9), i);
            z(j, i) = arma::accu(sm);
        }
    }
    return z;
}
", depends = "RcppArmadillo")

x <- matrix(1:150, ncol = 5)
mySum(x)
     [,1] [,2] [,3] [,4] [,5]
[1,]   55  355  655  955 1255
[2,]  155  455  755 1055 1355
[3,]  255  555  855 1155 1455

实际上,在 base R 中有一个名为 rowsum 的完全矢量化函数,可以非常有效地按组求和(附带说明,R 并不总是很慢,这主要取决于您如何使用它)。

x <- matrix(1:150, ncol = 5)
rowsum.default(x, cumsum(seq_len(nrow(x)) %% 10L == 1L), reorder = FALSE)
#   [,1] [,2] [,3] [,4] [,5]
# 1   55  355  655  955 1255
# 2  155  455  755 1055 1355
# 3  255  555  855 1155 1455

它肯定会比 Rcpp 版本慢,但在我的系统上,一个 20MM 行的 5 列矩阵运行不到 3 秒

x <- matrix(seq_len(1e8), ncol = 5)
dim(x)
## [1] 20000000        5
system.time(mySum(x))
# user  system elapsed 
# 0.72    0.24    0.96 
system.time(rowsum.default(x, cumsum(seq_len(nrow(x)) %% 10L == 1L), reorder = FALSE))
# user  system elapsed 
# 2.77    0.15    2.93 

编辑:根据您的评论,在测试您的 真实 数据集时 rowsum 更快 14=]版本

x <- matrix(seq_len(62400*4100), ncol = 4100)
dim(x)
## [1] 62400  4100
system.time(mySum(x))
# user  system elapsed 
# 1.53    1.03    2.57 
system.time(rowsum.default(x, cumsum(seq_len(nrow(x)) %% 10L == 1L), reorder = FALSE))
# user  system elapsed 
# 1.48    0.00    1.50