RcppArmadillo和Armadillo之间的性能差异

时间:2014-04-14 00:19:03

标签: r rcpp

我试图理解用RcppArmadillo编写的函数和使用Armadillo库在独立的C ++程序中编写的函数之间的性能差异。例如,考虑以下使用传统教科书公式计算线性模型系数的简单函数。

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

using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
void simpleLm(NumericMatrix Xr, NumericMatrix yr) {
   int n = Xr.nrow(), k = Xr.ncol();
   mat X(Xr.begin(), n, k, false);
   colvec y(yr.begin(), yr.nrow(), false);

   colvec coef = inv(X.t()*X)*X.t()*y;
}

使用1000000x100的{​​{1}}矩阵运行大约需要6秒钟。代码中的某些时间(未显示)表明所有时间都用于X计算。

coef

现在考虑一个用C ++编写的非常类似的函数,然后用X <- matrix(rnorm(1000000*100), ncol=100) y <- matrix(rep(1, 1000000)) system.time(simpleLm(X,y)) user system elapsed 6.028 0.009 6.040 编译。

g++

这里#include <iostream> #include <armadillo> #include <chrono> #include <cstdlib> using namespace std; using namespace arma; int main(int argc, char **argv) { int n = 1000000; mat X = randu<mat>(n,100); vec y = ones<vec>(n); chrono::steady_clock::time_point start = chrono::steady_clock::now(); colvec coef = inv(X.t()*X)*X.t()*y; chrono::steady_clock::time_point end = chrono::steady_clock::now(); chrono::duration<double, milli> diff = end - start; cout << diff.count() << endl; return 0; } 变量的计算只需要大约0.5秒,或者仅仅是使用RcppArmadillo时的1/12。

我使用Mac OS X 10.9.2和R 3.1.0,Rcpp 0.11.1和RcppArmadillo 0.4.200.0。我使用sourceCpp函数编译了Rcpp示例。独立的C ++示例使用Armadillo 4.200.0,我还使用Homebrew(coef)为Mac安装了Fortran编译器。

1 个答案:

答案 0 :(得分:4)

快速猜测:你的原生程序使用加速BLAS,你的R版本没有。

实际的&#34;矩阵数学&#34;由犰狳养殖到BLAS图书馆。使用RcppArmadillo,您可以获得R构建的内容。使用本机程序,也许您使用其他东西。它可能就像您的程序使用Accelerate库一样简单,而R不会 - 我真的不知道因为我不使用OS X.

但是为了证明,在我的(i7,Linux)机器上,时间几乎相同。

首先,你的程序没有改变:

edd@max:/tmp$ g++ -std=c++11 -O3 -o abiel abiel.cpp -larmadillo -llapack
edd@max:/tmp$ ./abiel 
2454
edd@max:/tmp$ 

其次,你的程序包含在R可以调用的内容中(见下文):

R> library(Rcpp)
R> sourceCpp("/tmp/abielviaR.cpp")
R> abielDemo()
2354.41
[1] TRUE
R> 

大致相同。

abielviaR.cpp的代码如下。

#include <RcppArmadillo.h>
#include <chrono>

using namespace std;
using namespace arma;

// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
bool abielDemo() {
    int n = 1000000;
    mat X = randu<mat>(n,100);
    vec y = ones<vec>(n);

    chrono::steady_clock::time_point start = chrono::steady_clock::now();
    colvec coef = inv(X.t()*X)*X.t()*y;
    chrono::steady_clock::time_point end = chrono::steady_clock::now();
    chrono::duration<double, milli> diff = end - start;
    Rcpp::Rcout << diff.count() << endl;

    return true;
}

PS你真的不应该通过(X&#39; X)^( - 1)X来计算OLS。