我试图理解用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编译器。
答案 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。