当运行多次执行glm函数的for循环时,RAM需求呈指数级增长

时间:2017-06-24 19:44:49

标签: r for-loop ram glm

我想检测数据集中的交互效果,我编写的代码可以创建所有可能的预测变量组合,分别适合每一对的gml模型,并存储模型和模型本身的重要统计数据。

我的数据集由100,000 +观察组成,我想检查200,000 +个可能的对组合。

代码运行没有错误,但问题是在第2,000次迭代后我的PC的60 GB RAM已经填满(当我开始运行代码时,有58 GB的空闲RAM) 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中删除并且应该受到保护的对象。

您的建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

考虑以下选项:

  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)
    
  2. 使用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()
    
  3. 最后,对于不需要设计/编程工作的大型操作,请考虑使用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")