簡體   English   中英

用應用函數替換在 R 中的 dfs 列表上迭代運行向后逐步回歸的 for 循環,以減少計算時間

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM