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