关于Rcpp的问题

时间:2015-03-07 09:03:55

标签: r rcpp

我在R中写了下面的计算 但是,这在许多“for循环”中使用很慢。

我尝试使用Rcpp编写类似的计算。 但这是一个错误。

请更正我的代码。

# R
data <- matrix(1: 100, ncol = 5, nrow = 20)

Y <- 10
X <- Y - 1
Z <- matrix(ncol = 1, nrow = nrow(data) - X) 

for (i in 1:(nrow(data) - X)){
  Z[i, ] <- sum(data[i: (i + X), ])
} 
> data
      [,1] [,2] [,3] [,4] [,5]
 [1,]    1   21   41   61   81
 [2,]    2   22   42   62   82
 [3,]    3   23   43   63   83
 [4,]    4   24   44   64   84
 [5,]    5   25   45   65   85
 [6,]    6   26   46   66   86
 [7,]    7   27   47   67   87
 [8,]    8   28   48   68   88
 [9,]    9   29   49   69   89
[10,]   10   30   50   70   90
[11,]   11   31   51   71   91
[12,]   12   32   52   72   92
[13,]   13   33   53   73   93
[14,]   14   34   54   74   94
[15,]   15   35   55   75   95
[16,]   16   36   56   76   96
[17,]   17   37   57   77   97
[18,]   18   38   58   78   98
[19,]   19   39   59   79   99
[20,]   20   40   60   80  100

> Z
       [,1]
 [1,] 2275
 [2,] 2325
 [3,] 2375
 [4,] 2425
 [5,] 2475
 [6,] 2525
 [7,] 2575
 [8,] 2625
 [9,] 2675
[10,] 2725
[11,] 2775



// Rcpp
#include <Rcpp.h> 
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix myRcpp(NumericMatrix data, NumericVector Y) {
  int X = Y - 1;
  int i;
  int nrow = data.nrow();
  Rcpp::NumericMatrix Z();

  for (i = 0; i < nrow - X; i++) {
    Z[i] = Rcpp::sum(data( Range(i, (i + X)) , _ ));
  }  

  return (Z);
}

后记 错误消息


sourceCpp("Rcpp/test.cpp")

g++ -m64 -I"C:/PROGRA~1/R/R-31~1.2/include" -DNDEBUG     -I"C:/PROGRA~1/R/R-31~1.2/library/Rcpp/include"  -I"d:/RCompile/CRANpkg/extralibs64/local/include"     -O2 -Wall  -mtune=core2 -c test.cpp -o test.o

test.cpp: In function 'Rcpp::NumericMatrix myRcpp(Rcpp::NumericMatrix, Rcpp::NumericVector)':

test.cpp:6:17: error: cannot convert 'Rcpp::sugar::Minus_Vector_Primitive<14, true, Rcpp::Vector<14, Rcpp::PreserveStorage> >' to 'int' in initialization

test.cpp:12:8: warning: pointer to a function used in arithmetic [-Wpointer-arith]

test.cpp:12:51: error: no matching function for call to 'sum(Rcpp::Matrix<14>::Sub)'

test.cpp:12:51: note: candidates are:

C:/PROGRA~1/R/R-31~1.2/library/Rcpp/include/Rcpp/sugar/functions/sum.h:98:32: note: template<bool NA, class T> Rcpp::sugar::Sum<13, NA, T> Rcpp::sum(const Rcpp::VectorBase<13, NA, VEC>&)

C:/PROGRA~1/R/R-31~1.2/library/Rcpp/include/Rcpp/sugar/functions/sum.h:103:33: note: template<bool NA, class T> Rcpp::sugar::Sum<14, NA, T> Rcpp::sum(const Rcpp::VectorBase<14, NA, VEC>&)

C:/PROGRA~1/R/R-31~1.2/library/Rcpp/include/Rcpp/sugar/functions/sum.h:108:32: note: template<bool NA, class T> Rcpp::sugar::Sum<10, NA, T> Rcpp::sum(const Rcpp::VectorBase<10, NA, VEC>&)

test.cpp:14:14: error: invalid conversion from 'Rcpp::NumericMatrix (*)() {aka Rcpp::Matrix<14> (*)()}' to 'int' [-fpermissive]

C:/PROGRA~1/R/R-31~1.2/library/Rcpp/include/Rcpp/vector/Matrix.h:67:5: error:   initializing argument 1 of 'Rcpp::Matrix<RTYPE, StoragePolicy>::Matrix(const int&) [with int RTYPE = 14, StoragePolicy = Rcpp::PreserveStorage]' [-fpermissive]
make: *** [test.o] Error 1

2 个答案:

答案 0 :(得分:3)

你有几个错误。大多数情况下,我建议解开复杂的表达式明确创建编译器/模板错误。

使用新代码,我得到:

R> sourceCpp("/tmp/so_question.cpp")

R> # R
R> data <- matrix(1: 100, ncol = 5, nrow = 20)

R> Y <- 10

R> X <- Y - 1

R> Z <- matrix(ncol = 1, nrow = nrow(data) - X) 

R> for (i in 1:(nrow(data) - X)) {
+   Z[i, ] <- sum(data[i: (i + X), ])
+ } 

R> #data
R> #Z
R> 
R> myRcpp(data, Y)
 [1] 2275 2325 2375 2425 2475 2525 2575 2625 2675 2725 2775
R> 

代码如下 - 我将R和C ++合并为一个文件。

#include <Rcpp.h> 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector myRcpp(NumericMatrix data, int y) {
  int x = y - 1;
  int i;
  int n = data.nrow();
  Rcpp::NumericVector z(n - x);

  for (i = 0; i < n - x; i++) {
    Rcpp::SubMatrix<REALSXP> sm = data( Range(i, (i + x)) , _ );
    Rcpp::NumericMatrix m(sm);
    double s = Rcpp::sum(m);
    z[i] = s;
  }  

  return z;
}


/*** R
# R
data <- matrix(1: 100, ncol = 5, nrow = 20)

Y <- 10
X <- Y - 1
Z <- matrix(ncol = 1, nrow = nrow(data) - X) 

for (i in 1:(nrow(data) - X)) {
  Z[i, ] <- sum(data[i: (i + X), ])
} 

#data
#Z

myRcpp(data, Y)
*/

我经常在RcppArmadillo中做这样的子设置问题......

编辑:为了完整性,在RcppArmadillo中,循环体减少到一行,因为我们可以使用子矩阵访问器 - 这里更简单,我们只选择行 - 我们总和(两次)和(明确地)转换为标量。

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h> 

// [[Rcpp::export]]
arma::rowvec myArma(arma::mat data, int y) {
  int x = y - 1;
  int n = data.n_rows;
  arma::rowvec z(n - x);

  for (int i = 0; i < n - x; i++) {
    z[i] = arma::as_scalar(arma::sum(arma::sum(data.rows(i, i+x))));
  }  

  return z;
}

正如Romain所说,一旦我们得到更大的矩阵,Rcpp中的额外副本就会有成本:

R> library(rbenchmark)

R> data <- matrix(1:1e6, ncol=50)

R> res <- benchmark(myRcpp(data, Y), myArma(data, Y))

R> res[,1:4]
             test replications elapsed relative
2 myArma(data, Y)          100   1.555    1.000
1 myRcpp(data, Y)          100   6.860    4.412
R> 

答案 1 :(得分:0)

因为我看到你和答案都为每一行重复相同的计算(行总和)Y次。这是一个矢量化解决方案,

data %>%
  rowSums %>%
  cumsum %>%
  {. - lag(., Y)}

(来自包magrittr的%&gt;%,来自dplyr的滞后方法)应该做你想要的,它甚至比Rcpp快一点。

Unit: milliseconds
             expr       min        lq      mean    median        uq       max neval cld
  myArma(data, Y) 10.363077 11.633387 17.963248 12.233787 14.772540 131.67896   100   b
 vectorized(data)  3.172276  3.284239  5.492879  3.441609  4.664644  63.96084   100  a 

你提到你最终想要使用sd而不是sum,但即使在那种情况下缓存平方和也会节省很多时间。

data %>%
  {(. - mu)^2} %>%
  rowSums %>%
  cumsum %>%
  {. - lag(.,Y)} %>%
  divide_by( Y*NCOL(data) - 1 )

以mu为组意味着您可以使用其他解决方案。

这种方式的C ++实现当然会比R更快但我不认为你可以打败上面的代码以简洁。 :)

侨, 斯蒂芬

编辑:根据数据的结构和大小,您可能会遇到从缩写减去滞后的集合中减去消除的问题(即,如果cumsum比单行总和大16个数量级,则用完了有效数字)。在这种情况下,您可以使用RcppRoll中的roll_sum替换该步骤。

它实际上甚至更短的解决方案,我只是没有RcppRoll的经验,并且不能说是否存在问题或陷阱

data %>%
  rowSums %>%
  roll_sum(Y)