对于我正在构建的应用程序,我需要对大型数据集运行线性回归以获取残差。例如,一个数据集的维度超过100万x 20k。对于较小的数据集,我使用fastLm
包中的RcppArmadillo
- 这对于那些目前非常有用。随着时间的推移,这些数据集也将超过100万行。
我的解决方案是使用稀疏矩阵和Eigen。我无法找到在RcppEigen中使用SparseQR的好例子。基于许多小时的阅读(例如rcpp-gallery,stackoverflow,rcpp-dev mailinglist,eigen docs,rcpp-gallery,stackoverflow以及我忘记的更多内容但肯定已经读过)我写了下面这段代码;
(注意:我的第一个c ++程序 - 请保持良好:) - 欢迎任何改进建议)
// [[Rcpp::depends(RcppEigen)]]
#include <RcppEigen.h>
using namespace Rcpp;
using namespace Eigen;
using Eigen::Map;
using Eigen::SparseMatrix;
using Eigen::MappedSparseMatrix;
using Eigen::VectorXd;
using Eigen::SimplicialCholesky;
// [[Rcpp::export]]
List sparseLm_eigen(const SEXP Xr,
const NumericVector yr){
typedef SparseMatrix<double> sp_mat;
typedef MappedSparseMatrix<double> sp_matM;
typedef Map<VectorXd> vecM;
typedef SimplicialCholesky<sp_mat> solver;
const sp_mat Xt(Rcpp::as<sp_matM>(Xr).adjoint());
const VectorXd Xty(Xt * Rcpp::as<vecM>(yr));
const solver Ch(Xt * Xt.adjoint());
if(Ch.info() != Eigen::Success) return "failed";
return List::create(Named("betahat") = Ch.solve(Xty));
}
这适用于例如;
library(Matrix)
library(speedglm)
Rcpp::sourceCpp("sparseLm_eigen.cpp")
data("data1")
data1$fat1 <- factor(data1$fat1)
mm <- model.matrix(formula("y ~ fat1 + x1 + x2"), dat = data1)
sp_mm <- as(mm, "dgCMatrix")
y <- data1$y
res1 <- sparseLm_eigen(sp_mm, y)$betahat
res2 <- unname(coefficients(lm.fit(mm, y)))
abs(res1 - res2)
然而,对于我的大型数据集(正如我预期的那样),它失败了。我的初衷是使用SparseQR
作为求解器,但我不知道如何实现它。
所以我的问题 - 有人可以帮我用RcppEigen实现稀疏矩阵的QR分解吗?
答案 0 :(得分:3)
如何使用Eigen编写稀疏解算器有点通用。这主要是因为稀疏求解器类的设计非常好。他们提供guide explaining their sparse solver classes。由于问题集中在SparseQR,因此文档指出初始化解算器需要两个参数:SparseMatrix类类型和OrderingMethods类,它们规定了支持的填充减少排序方法。
考虑到这一点,我们可以提出以下建议:
// [[Rcpp::depends(RcppEigen)]]
#include <RcppEigen.h>
#include <Eigen/SparseQR>
// [[Rcpp::export]]
Rcpp::List sparseLm_eigen(const Eigen::MappedSparseMatrix<double> A,
const Eigen::Map<Eigen::VectorXd> b){
Eigen::SparseQR <Eigen::MappedSparseMatrix<double>, Eigen::COLAMDOrdering<int> > solver;
solver.compute(A);
if(solver.info() != Eigen::Success) {
// decomposition failed
return Rcpp::List::create(Rcpp::Named("status") = false);
}
Eigen::VectorXd x = solver.solve(b);
if(solver.info() != Eigen::Success) {
// solving failed
return Rcpp::List::create(Rcpp::Named("status") = false);
}
return Rcpp::List::create(Rcpp::Named("status") = true,
Rcpp::Named("betahat") = x);
}
注意:在这里,我们创建一个列表,该列表始终传递一个应该首先检查的<{1}}变量。这表明收敛是否发生在两个方面:分解和解决。如果全部检出,则我们传递status
系数。
测试脚本:
betahat
输出:
library(Matrix)
library(speedglm)
Rcpp::sourceCpp("sparseLm_eigen.cpp")
data("data1")
data1$fat1 <- factor(data1$fat1)
mm <- model.matrix(formula("y ~ fat1 + x1 + x2"), dat = data1)
sp_mm <- as(mm, "dgCMatrix")
y <- data1$y
res1 <- sparseLm_eigen(sp_mm, y)
if(res1$status != TRUE){
stop("convergence issue")
}
res1_coef = res1$betahat
res2_coef <- unname(coefficients(lm.fit(mm, y)))
cbind(res1_coef, res2_coef)