Rcpparmadillo matrixproduct性能

时间:2017-06-22 08:58:09

标签: r rcpp

当我向代码中添加arma::mat P(X * arma::inv(X.t() * X) * X.t());时,有人可以向我解释为什么计算会变慢得多。上次我对代码进行基准测试时,平均值增长了164倍。

// [[Rcpp::depends(RcppArmadillo)]]

#include <RcppArmadillo.h>
using namespace Rcpp;

//[[Rcpp::export]]
List test1(DataFrame data, Language formula, String y_name) {
  Function model_matrix("model.matrix");
  NumericMatrix x_rcpp = model_matrix(formula, data);
  NumericVector y_rcpp = data[y_name];
  arma::mat X(x_rcpp.begin(), x_rcpp.nrow(), x_rcpp.ncol());
  arma::colvec Y(y_rcpp.begin(), y_rcpp.size());

  arma::colvec coef = inv(X.t() * X) * X.t() * Y;
  arma::colvec resid = Y - X * coef;
  arma::colvec fitted = X * coef;

  DataFrame data_res = DataFrame::create(_["Resid"] = resid,
                    _["Fitted"] = fitted);

  return List::create(_["Results"] = coef,
                      _["Data"] = data_res);
}

//[[Rcpp::export]]
List test2(DataFrame data, Language formula, String y_name) {
  Function model_matrix("model.matrix");
  NumericMatrix x_rcpp = model_matrix(formula, data);
  NumericVector y_rcpp = data[y_name];
  arma::mat X(x_rcpp.begin(), x_rcpp.nrow(), x_rcpp.ncol());
  arma::colvec Y(y_rcpp.begin(), y_rcpp.size());

  arma::colvec coef = inv(X.t() * X) * X.t() * Y;
  arma::colvec resid = Y - X * coef;
  arma::colvec fitted = X * coef;

  arma::mat P(X * arma::inv(X.t() * X) * X.t());

  DataFrame data_res = DataFrame::create(_["Resid"] = resid,
                                         _["Fitted"] = fitted);

  return List::create(_["Results"] = coef,
                      _["Data"] = data_res);
}

/*** R
data <- data.frame(Y = rnorm(10000), X1 = rnorm(10000), X2 = rnorm(10000), X3 = rnorm(10000))
microbenchmark::microbenchmark(test1(data, Y~X1+X2+X3, "Y"),
                               test2(data, Y~X1+X2+X3, "Y"), times = 10)
  */

祝你好运, 雅各布

2 个答案:

答案 0 :(得分:1)

好问题。不完全确定为什么速度会增加到我做过的几个音符之外。所以,请注意。

考虑到这里使用的 n 是10000而 p 是3。

让我们看一下所要求的操作。我们将从coef或beta_hat操作开始:

Beta_[p x 1] = (X^T_[p x n] * X_[n x p])^(-1) * X^T_[p x n] * Y_[n x 1]

查看P或投影/帽子矩阵:

P_[n x n] = X_[n x p] * (X^T_[p x n] * X_[n x p])^(-1) * X^T_[p x n]

因此,这里的N矩阵足够大于先前矩阵。矩阵乘法通常由O(n ^ 3)(幼稚的教科书乘法)控制。所以,这可能解释了时间的大幅增加。

除此之外,还有重复的计算涉及

(X^T_[p x n] * X_[n x p])^(-1) * X^T_[p x n]
test2

导致重新计算。这里的主要问题是反向是最昂贵的操作。

此外,关于使用inv API条目表示:

  
      
  • 如果知道矩阵A是对称正定,则使用inv_sympd()更快
  •   
  • 如果知道矩阵A是对角线,则使用inv(diagmat(A))
  •   
  • 解决线性方程组,如Z = inv(X)* Y,使用solve()更快更准确
  •   

第三点在这种情况下特别感兴趣,因为它为inv(X.t() * X)*X.t() =&gt;提供了更优化的例程。 solve(X.t() * X, X.t())

答案 1 :(得分:1)

你所做的非常接近fastLm()多年来我多次修改过的。由此我们可以得出一些结论:

  1. 不要X(X&#39; X)^ 1 X&#39;直。使用solve()
  2. 不要永远处理公式对象。使用Xy的矩阵和向量。
  3. 以下是benchmark example,说明了解析公式如何破坏矩阵代数中的所有增益。

    顺便说一句,R本身已经为排名不足的矩阵进行了调整。这有助于变形矩阵;在许多&#34;正常&#34;你应该没问题。