R:对数百个变量进行剩余化的最快方法
我有一个大的数据集,约30m个观测值,约800个变量,我需要对700个变量进行残差化,方法是将每个变量回归到3个变量上,然后存储残差。以下是我目前正在做的事情:R:对数百个变量进行剩余化的最快方法,r,data.table,regression,lapply,R,Data.table,Regression,Lapply,我有一个大的数据集,约30m个观测值,约800个变量,我需要对700个变量进行残差化,方法是将每个变量回归到3个变量上,然后存储残差。以下是我目前正在做的事情: io_d[, (vars_to_residualize_list) := lapply(.SD, function(X) {lm(X ~ X1 + X2 + X3)$residuals}), .SDcols = vars_to_residualize] 其中,vars_to_residualize是要
io_d[, (vars_to_residualize_list) := lapply(.SD,
function(X) {lm(X ~ X1 + X2 + X3)$residuals}),
.SDcols = vars_to_residualize]
其中,vars_to_residualize是要残差化的变量列表,vars_to_residualize_列表是残差的新名称列表
这需要大约70个小时来完成所有变量
有没有更快的方法 也许这会显著地帮助您减少时间;稍微修改fLmSEXP的代码,以便能够提取残差
library(Rcpp)
library(RcppArmadillo)
library(rbenchmark)
## start from SEXP, most conversions, longest code
src <- '
Rcpp::List fLmSEXP(SEXP Xs, SEXP ys) {
Rcpp::NumericMatrix Xr(Xs);
Rcpp::NumericVector yr(ys);
int n = Xr.nrow(), k = Xr.ncol();
arma::mat X(Xr.begin(), n, k, false);
arma::colvec y(yr.begin(), yr.size(), false);
// fit model y ~ X, extract residuals
arma::colvec coef = arma::solve(X, y);
arma::colvec res = y - X*coef;
// return the results
return Rcpp::List::create(Rcpp::Named("coefficients")=coef,Rcpp::Named("res")=res);
}
'
cppFunction(code=src, depends="RcppArmadillo")
我希望这会有帮助,或者至少给你一个方法。X1、X2和X3都是连续的吗?稠密的您肯定应该在700个变量之间进行并行化。也可以向下跳过某个级别,直接使用lm.fit,而不是创建整个lm对象。阅读一下lm的源代码,了解一下这一点。它们都是因素。并行化是一个好主意。我将研究lm.fit。如果X1、X2和X3都是因子,你不是在3个变量上回归,而是在n1-1+n2-1+n3-1变量上回归,其中nk是Xk的水平数。好处是这种回归可能非常稀疏,您可以使用sparse.model.matrix&稀疏回归方法可能会快得多。如果你对矩阵代数/回归技术很小心,你甚至可能根本不需要计算设计矩阵。最后一件事——如果X1:X3在你的700个回归中总是相同的,你应该只使用model.matrix或sparse.model.matrix一次`来创建和存储你的设计矩阵。如果这个对象是重复的,不需要费心创建700次。看起来很有趣-我会尝试一下!
df <- data.frame(replicate(3,sample(1:4,300000,rep=TRUE)))
df = cbind(X = rnorm(300000),df)
head(df)
X X1 X2 X3
1 0.6269854 1 4 3
2 0.4641201 1 1 4
3 -0.5625020 3 1 4
4 0.0452215 2 1 2
5 2.2453335 3 3 2
6 0.4045328 1 3 3
m <- as.matrix(cbind(X = df[,1],cbind(I = 1,df[,2:4])))
benchmark(
lm_res = lm(X ~ X1 + X2 + X3, data = df)$residuals,
flm_res = fLmSEXP(m[,2:5],m[,1])$res, replications = 100)[,1:4]
test replications elapsed relative
2 flm_res 100 4.14 1.00
1 lm_res 100 12.46 3.01