首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >最小二乘的SparseQR

最小二乘的SparseQR
EN

Stack Overflow用户
提问于 2017-04-12 20:12:41
回答 1查看 3K关注 0票数 1

对于我正在构建的应用程序,我需要在大型数据集上运行线性回归,以获得剩余值。例如,一个数据集的维数超过100万×20k。对于较小的数据集,我目前使用的是fastLm包中的RcppArmadillo包(这对这些数据集非常有用)。随着时间的推移,这些数据集也将超过100万行。

我的解决方案是使用稀疏矩阵和特征。我找不到一个在RcppEigen中使用RcppEigen的好例子。基于许多小时的阅读(例如,rcpp画廊堆栈过流rcpp邮件列表艾根博士rcpp画廊堆栈过流以及许多我已经忘记但确实读过的东西),我编写了以下代码;

(注:我的第一个c++项目-请注意:) --欢迎任何改进的建议)

代码语言:javascript
复制
// [[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));
}

例如,这样做是可行的;

代码语言:javascript
复制
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分解吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-12 22:47:59

如何使用本征编写稀疏求解程序有点通用。这主要是因为稀疏求解器类设计得非常好。他们提供一个解释稀疏求解器类的指南。由于问题集中在SparseQR上,文档表明初始化求解程序需要两个参数: SparseMatrix类类型和OrderingMethods类,它们指示支持的填充减少排序方法。

考虑到这一点,我们可以提出以下几点:

代码语言:javascript
复制
// [[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);
}

注意:在这里,我们创建了一个列表,它总是传递一个应该首先检查的命名status变量。这表明收敛是否发生在两个领域:分解和求解。如果所有检查完毕,那么我们将通过betahat系数。

测试脚本:

代码语言:javascript
复制
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)

输出:

代码语言:javascript
复制
        res1_coef    res2_coef
[1,]  1.027742926  1.027742926
[2,]  0.142334262  0.142334262
[3,]  0.044327457  0.044327457
[4,]  0.338274783  0.338274783
[5,] -0.001740012 -0.001740012
[6,]  0.046558506  0.046558506
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43378812

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档