当我向代码中添加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)
*/
祝你好运, 雅各布
答案 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()
多年来我多次修改过的。由此我们可以得出一些结论:
solve()
。X
和y
的矩阵和向量。以下是benchmark example,说明了解析公式如何破坏矩阵代数中的所有增益。
顺便说一句,R本身已经为排名不足的矩阵进行了调整。这有助于变形矩阵;在许多&#34;正常&#34;你应该没问题。