【问题标题】:Apply function in R causes memory allocation errorR中的应用函数导致内存分配错误
【发布时间】:2012-08-09 20:40:28
【问题描述】:

我正在尝试对 R 中数据框的每一行进行计算,并将计算结果作为新列添加到框架中。我开始使用“by”函数,但计算速度非常慢,所以我改用“apply”函数。我想它的工作方式是使用我的函数运行 apply,将输出保存到变量并将该数据附加到原始数据帧。

我创建了一个函数来计算保险计划的期限长度并返回该值,该函数在样本数据集上运行良好。当我使用较大的数据集时,出现“无法分配大小的向量 ...”的错误。我知道很多人建议使用更多的 RAM,但我已经有 16GB 的内存,并且在 R 中加载了整个数据集,我的计算机说它只使用了 7.7GB 的内存。该数据集有 44 列,约 1100 万条记录,所以我看不到再添加一列数据会占用 8GB 内存吗?

朝着正确方向的任何一点都会很棒。


以下是我正在使用的功能:

get_term_length <- function(row_data){

    # convert values to dates
    expiration_date <- as.Date( row_data[42] )
    start_date <- as.Date( row_data[43] )
    cancellation_date <- as.Date( row_data[44] )

    # check to see if the cancellation date is NA - just use entire policy length
    if( is.na(cancellation_date) ){
        return( expiration_date - start_date) )
    }

    # check to see if policy was cancelled early
    if(cancellation_date < expiration_date){
        return( cancellation_date - start_date )
    }

    # the policy was for the entire term
    else{
        return( expiration_date - start_date )
    }

}

我一直通过调用来运行函数:

tmp <- apply(policy_data, 1, get_term_length)

【问题讨论】:

  • 查看data.table 和运算符:=(例如,使用标签[r][data.table] 在SO 上搜索)。
  • 要点:R 本质上是一种函数式语言 -> 通常,函数不会就地修改对象 -> 修改你说的那个 7.7Gb 数据框?当然!我会准备一个副本来工作! -> 你现在已经填满了超过 15Gb。砰! (专家,请不要吹毛求疵!我保持基本。)
  • 感谢joran的解释;这就说得通了。我假设 apply 只会将行对象的副本传递给函数,但我猜不是。
  • 基本问题可能是您熟悉 SAS 或 SPSS 的 IF 函数的隐式循环。 R if()函数不执行循环操作,所以需要使用ifelse()。

标签: r data.table


【解决方案1】:

@Dwin 暗示的data.table 解决方案

 library(data.table)
 policy_data <- as.data.table(policy_data)

  # set the date  columns to be  IDate (the exact form of this will depend
  # on the format they are currently in

  policy_data[, cancellation_date := as.IDate(cancellation_date)]
  policy_data[, start_date := as.IDate(start_date)]
  policy_data[, end_date := as.IDate(end_date)]
  # create a column which is an indicator for NA 

  policy_data[, isna := is.na(cancellation_date)]


  setkey(policy_data, isna)

  policy_data[J(TRUE), tmp := expiration_date - start_date]
  policy_data[J(FALSE), tmp := pmin(cancellation_date - start_date, expiration_date-start_date)]   

【讨论】:

    【解决方案2】:

    “经验法则”是您需要 _at_least_ 3 倍于您正在使用的最大对象的连续 RAM,因此您可能需要更频繁地重新启动并限制数量系统上其他正在运行的应用程序。我对拥有 32 GB 的硬件感到相当满意,并且正在研究基于 5-6 GB 大小的数据对象的回归模型。

    (我也通常对添加一列数据所花费的时间不满意,所以我有时会创建“外部”或“平行”向量,通常使用 ave() 函数来进行表操作。或者我使用数据的子集()-s。)R 专家正在研究此问题,但尚未公布解决方案。 Matthew Dowle 开发了“data.table”包来解决这个问题(并且速度非常快),但代价是“[”操作需要不同的语义。

    您可以在此处找到其他讨论内存要求的帖子。最常被投票的可能是: Tricks to manage the available memory in an R session 。我有点惊讶,那里的答案中没有提到 data.table 包。

    编辑:我看到了您接受的答案(这实际上是处理数据子集的一个实例),但我认为这与您之前得到的结果不同。要获得该结果,您需要以下内容:

    tmp <- with(policy_data, 
              ifelse( is.na(cancellation_date), expiration_date - start_date , # else
                pmin(as.Date(cancellation_date)-as.Date(start_date),
                     as.Date(expiration_date)-as.Date(start_date)
                     ))
    

    如果您希望ifelse 函数正常工作,您不想在pmin 中使用“na.rm=TRUE”。

    【讨论】:

    • 感谢您的回复!我一定会阅读您分享的链接。
    • 然后搜索:'[r] memory limits' 或类似的搜索词。人们偶尔遇到的向量(以及只是折叠向量的矩阵)的长度有 2^31-1 的限制。
    • 我也很惊讶,谢谢。已为该链接添加了答案。
    【解决方案3】:

    看起来您不需要整个 data.frame。只需提取所需的 3 列,即可恢复大部分内存。

    tmp <- with(policy_data, 
                pmin(as.Date(cancellation_date)-as.Date(start_date),
                     as.Date(expiration_date)-as.Date(start_date),
                     na.rm=TRUE))
    

    【讨论】:

    • 这也会快上百倍。
    • 这非常有效!它运行速度超快,处理整个数据集的速度比使用该函数的样本集更快。哇!谢谢!
    • 不客气。在 R 中,几乎所有东西都有一个内置函数来做你想做的事情。问题总是在找到那个函数。
    猜你喜欢
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    相关资源
    最近更新 更多