[英]Replacing a for-loop which iteratively runs Backward Stepwise Regressions on a list of dfs in R with an apply function to reduce compute time
R 腳本和其中包含多個 csv 文件格式數據集的文件夾的簡化版本都可以在我的 GitHub 存儲庫中找到,在此鏈接中。
在我名為“LASSO 代碼”的腳本中,將一個包含 N 個 csv 文件格式數據集的文件夾加載到 R 並將它們全部分配給一個名為“數據集”的列表后,我運行了以下代碼以適應 N 個 LASSO 回歸,一個到每個數據集:
set.seed(11) # to ensure replicability
LASSO_fits <- lapply(dfs, function(i)
enet(x = as.matrix(select(i, starts_with("X"))),
y = i$Y, lambda = 0, normalize = FALSE))
現在,我想為向后消除逐步回歸復制相同的過程,我們將通過使用統計庫中的 step() 函數來保持簡單)使用另一個應用函數而不是必須使用循環。 問題是這樣的,我唯一知道如何做到這一點是在運行它之前先初始化或准備它,方法是首先建立:
set.seed(100) # for reproducibility
full_fits <- vector("list", length = length(dfs))
Backward_Stepwise_fits <- vector("list", length = length(dfs))
然后才擬合所有 Backward_Stepwise_fits,但我不知道如何將 full_fits 和 Backward_Stepwise_fits 放入同一個應用函數中,我能想到的唯一方法是使用 for 循環並將它們堆疊在彼此內部它,但那將是非常低效的計算。 NI 將運行這兩個數據集的數量是 260,000!
我寫了一個 for-loop,它確實運行了,但只用了 12 個小時就完成了 58,500 個數據集的運行,速度慢得令人無法接受。 我使用的代碼如下:
set.seed(100) # for reproducibility
for(i in seq_along(dfs)) {
full_fits[[i]] <- lm(formula = Y ~ ., data = dfs[[i]])
Backward_Stepwise_fits[[i]] <- step(object = full_fits[[i]],
scope = formula(full_fits[[i]]),
direction = 'backward', trace = 0) }
我嘗試了以下操作,但在控制台中收到了相應的錯誤消息:
> full_model_fits <- lapply(datasets, function(i)
+ lm(formula = Y ~ ., data = datasets))
Error in terms.formula(formula, data = data) :
duplicated name 'X1' in data frame using '.'
有沒有想過將整個事情並行化?
首先,您可以更簡潔地定義代碼。
system.time(
res <- lapply(lst, \(X) {
full <- lm(Y ~ ., X)
back <- step(full, scope=formula(full), dir='back', trace=FALSE)
})
)
# user system elapsed
# 3.895 0.008 3.897
system.time(
res1 <- lapply(lst, \(X) step(lm(Y ~ ., X), dir='back', trace=FALSE))
)
# user system elapsed
# 3.820 0.016 3.833
stopifnot(all.equal(res, res1))
結果相等,但沒有時間差異。
現在,使用parallel::parLapply
。
library(parallel)
CL <- makeCluster(detectCores() - 1L)
clusterExport(CL, c('lst'))
system.time(
res2 <- parLapply(CL, lst, \(X) step(lm(Y ~ ., X), dir='back', trace=FALSE))
)
# user system elapsed
# 0.075 0.032 0.861
stopCluster(CL)
stopifnot(all.equal(res, res2))
在這台機器上大約快 4.5 倍。
您的錯誤duplicated name 'X1' in data frame using '.'
意味着,在您的某些數據集中,有兩列名為"X1"
。 找到它們的方法如下:
names(lst$dat6)[9] <- 'X1' ## producing duplicated column X1 for demo
sapply(lst, \(x) anyDuplicated(names(x)))
# dat1 dat2 dat3 dat4 dat5 dat6 dat7 dat8 dat9 dat10 dat11
# 0 0 0 0 0 9 0 0 0 0 0
# ...
結果顯示,在數據集dat6
中,第9
列是(第一個)重復項。 其他都是干凈的。
數據:
n <- 50
lst <- replicate(n, {dat <- data.frame(matrix(rnorm(500*30), 500, 30))
cbind(Y=rowSums(as.matrix(dat)%*%rnorm(ncol(dat))) + rnorm(nrow(dat)), dat)}, simplify=FALSE) |>
setNames(paste0('dat', seq_len(n)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.