我想检测数据集中的交互效果,我编写的代码可以创建所有可能的预测变量组合,分别适合每一对的gml模型,并存储模型和模型本身的重要统计数据。
我的数据集由100,000 +观察组成,我想检查200,000 +个可能的对组合。
代码运行没有错误,但问题是在第2,000次迭代后我的PC的60 GB RAM已经填满(当我开始运行代码时,有58 GB的空闲RAM)
对于可重现的示例,我将使用mtcars数据集:
data(mtcars)
setDT(mtcars)
predictor_names <- setdiff(names(mtcars) , "am")
combinations <- combn(length(predictor_names) , 2)
combinations <- t(combinations)
combinations <- as.data.frame(combinations)
models_glm <- list()
Coefficients_dt <- data.table(Predictor_1 = character() , Predictor_2 = character(), dev_ratio = numeric() ,
Estimate = numeric(), p.value = numeric())
system.time(
for (i in (1 : (nrow(combinations) - 1 ))) {
# Extracts the index positions of the names of the pairs
#----------------------------------------------------------
m <- combinations[i, 1]
k <- combinations[i, 2]
# Extracts the names of the predictors from a vector that holds them
#------------------------------------------------------------------------
m_name <- predictor_names[m]
k_name <- predictor_names[k]
# Uses the names of the predictors to construct a formula
#------------------------------------------------------------------
formula_glm <- paste0( "am ~ " , m_name, " * " , k_name)
formula_glm <- as.formula(formula_glm )
# Passes the formula to a glm model
#-------------------------------------------------------------------
model <- glm(formula_glm , mtcars, family = "binomial")
# Stores the model to a list
#-------------------------------------------------------------------
models_glm [[ paste0(m_name , "_*_" , k_name)]] <- model
# Calculates the dev.ratio
#---------------------------------------------------------------
residual.deviance <- model$deviance
null.deviance <- model$null.deviance
dev.ratio <- (null.deviance - residual.deviance) / null.deviance
# Extracts the Coefficient estimate and p-value from the model
#-------------------------------------------------------------------
Coefficients_df <- as.data.frame(summary(model)$coefficients)
names(Coefficients_df) <- c("Estimate" , "SE" , "Z", "p.value")
if(dim(Coefficients_df)[1] == 4){
Coefficients_dt <- rbind(Coefficients_dt , data.table(
Predictor_1 = m_name ,
Predictor_2 = k_name,
dev_ratio = dev.ratio,
Estimate = Coefficients_df$Estimate[4] ,
p.value = Coefficients_df$p.value[4]
))
}
}
)
我该怎么做才能解决这个问题?
即。我想了解问题的根本原因:什么占用RAM空间?与可用RAM相比,所涉及的对象不是很大。具体来说,Coefficients_dt data.table最多将变为200,000行×5列。
因为迭代在for循环中建立,所以其他东西正在进行并消耗越来越多的RAM。
接下来我想了解在for-loop的执行过程中我是否可以采取一些操作 - 例如命令嵌套在for循环中的if语句中 - 这将释放RAM空间,同时可能保存任何将从RAM中删除并且应该受到保护的对象。
您的建议将不胜感激。
答案 0 :(得分:1)
考虑以下选项:
预先分配任何所需的对象,而不是迭代地使用值扩展它,这需要机器使用内存重新分配空间,您可以为现有元素赋值:
models_glm <- vector(mode = "list", length = 45)
事实上,甚至考虑事先命名元素:
pnames <- sapply(1:nrow(combinations)-1, function(i){
paste0(predictor_names[combinations[i,1]], "_*_",
predictor_names[combinations[i,2]])
})
models_glm <- setNames(vector(mode="list", length=45), pnames)
使用data.table::rbindlist()
在一次调用中将数据表列绑定到一个大型数据帧,而不是在循环内逐行扩展数据帧。下面使用lapply
返回一个等于输入长度的对象。另外,请注意空数据表以避免NULL
返回rbindlist
:
dTList <- lapply(seq(nrow(combinations)-1), function(i) {
#... same as above
# use <<- operator to update environment object outside function
models_glm[[paste0(m_name, "_*_", k_name)]] <<- model
#...
Coefficients_df <- setNames(as.data.frame(summary(model)$coefficients),
c("Estimate", "SE", "Z", "p.value"))
if(dim(Coefficients_df)[1] == 4){
data.table(
Predictor_1 = m_name ,
Predictor_2 = k_name,
dev_ratio = dev.ratio,
Estimate = Coefficients_df$Estimate[4],
p.value = Coefficients_df$p.value[4]
)
} else {
# RETURN EMPTY DT
data.table(
Predictor_1 = character(),
Predictor_2 = character(),
dev_ratio = numeric(),
Estimate = numeric(),
p.value = numeric()
)
}
})
coefficients <- data.table::rbindlist(dTlist)
rm(dTlist)
gc()
最后,对于不需要设计/编程工作的大型操作,请考虑使用RStudio或Rgui上的自动Rscript.exe,因为这些后续程序需要额外的资源。下面是一个命令行,可以从PowerShell,CMD提示符或批处理(.bat)文件运行,假设Rscript是环境PATH变量:
Rscript "C:\Path\To\ModelCoefficientDataBuild.R"
具体来说,Windows上的RStudio rsession.exe在会话结束之前,一旦获得内存,往往不会将内存释放回操作系统。见RStudio forum posts on subject。当然,请务必将所需对象保存到磁盘以供日后使用:
saveRDS(coefficients, "coefficients_datatable.rds")