R - 为啥向数据表添加 1 列几乎会使使用的峰值内存增加一倍?

Posted

技术标签:

【中文标题】R - 为啥向数据表添加 1 列几乎会使使用的峰值内存增加一倍?【英文标题】:R - Why adding 1 column to data table nearly doubles peak memory used?R - 为什么向数据表添加 1 列几乎会使使用的峰值内存增加一倍? 【发布时间】:2015-04-05 12:07:43 【问题描述】:

从两位好心人那里得到help后,我设法从数据框+plyr切换到数据表。

情况和我的问题

随着我的工作,我注意到当我使用 := 向我的数据集添加 1 个新列时,峰值内存使用量几乎翻了一番,从 3.5GB 到 6.8GB(根据 Windows 任务管理器)包含约 200K 行乘 2.5K 列。

然后我尝试了 200M 行乘 25 列,增加了从 6GB 到 7.6GB,然后在 gc() 之后下降到 7.25GB。

特别是关于添加新列,Matt Dowle 本人提到here:

使用它的 := 运算符,您可以:

Add columns by reference
Modify subsets of existing columns by reference, and by group by reference
Delete columns by reference

这些操作都不会复制(可能很大)data.table 全部,甚至一次都没有。

问题 1:如果根本不复制 data.table,为什么要为具有 2.5K 列的 DT 添加单列“NAs”加倍使用的峰值内存?

问题2:为什么DT为200M x 25时不会发生翻倍?我没有为此包含打印屏幕,但请随时更改我的代码并尝试。

使用测试代码打印内存使用情况

    干净重启,打开 RStudio 和 MS Word - 已使用 103MB

    在运行 DT 创建代码之后但在添加列之前 - 使用了 3.5GB

    在添加 1 列填充 NA 之后,但在 gc() 之前 - 使用了 6.8GB

    运行 gc() 后 - 使用了 3.5GB

测试代码

为了进行调查,我编写了以下与我的数据集非常相似的测试代码:

library(data.table)
set.seed(1)

# Credit: Dirk Eddelbuettel's answer in 
# https://***.com/questions/14720983/efficiently-generate-a-random-sample-of-times-and-dates-between-two-dates
RandDate <- function(N, st="2000/01/01", et="2014/12/31")  
  st <- as.POSIXct(as.Date(st))
  et <- as.POSIXct(as.Date(et))
  dt <- as.numeric(difftime(et,st,unit="sec"))
  ev <- runif(N, 0, dt)
  rt <- as.character( strptime(st + ev, "%Y-%m-%d") )


# Create Sample data
TotalNoCol <- 2500
TotalCharCol <- 3
TotalDateCol <- 1
TotalIntCol <- 600
TotalNumCol <- TotalNoCol - TotalCharCol - TotalDateCol - TotalIntCol
nrow <- 200000

ColNames = paste0("C", 1:TotalNoCol)

dt <- as.data.table( setNames( c(

  replicate( TotalCharCol, sample( state.name, nrow, replace = T ), simplify = F ), 
  replicate( TotalDateCol, RandDate( nrow ), simplify = F ), 
  replicate( TotalNumCol, round( runif( nrow, 1, 30 ), 2), simplify = F ), 
  replicate( TotalIntCol, sample( 1:10, nrow, replace = T ), simplify = F ) ), 

    ColNames ) )

gc()

# Add New columns, to be run separately
dt[, New_Col := NA ]  # Additional col; uses excessive memory?

研究完成

我没有发现太多关于 DT 的内存使用的讨论,有很多列,只有this,但即便如此,它也不是专门关于内存的。

关于大型数据集 + 内存使用的大多数讨论都涉及行数非常大但列相对较少的 DT。

我的系统

Intel i7-4700 4 核/8 线程; 16GB DDR3-12800 内存; Windows 8.1 64 位; 500GB 7200rpm 硬盘; 64 位 R;数据表ver 1.9.4

免责声明

请原谅我使用“非 R”方法(即任务管理器)来测量使用的内存。 R 中的内存测量/分析是我还没有弄清楚的东西。


编辑 1:更新到数据表 1.9.5 版并重新运行后。不幸的是,问题仍然存在。

【问题讨论】:

@shadow,我认为您的意思是tables(),感谢您向我强调此功能-我以前不知道。我浏览了函数描述,它似乎报告了 DT 使用的最终内存,而不是处理期间使用的最大内存(即包括工作内存)。不确定这些数字与任务管理器报告的数字有何关系。如果我错了,请纠正我。 仅供参考,?tables 将您带到帮助页面,所以这是故意的。同样,您可以输入 ?truelength 以获取有关 data.tables 如何处理内存的信息。 这很可能是由于this bug, #921,它已在1.9.5 中修复。发生了一些不必要的副本(我认为是从1.9.0 回归)。我建议在1.9.5 上再试一次。 嗯,似乎发生了一些复制,而只是从内部函数返回一个值。将尝试找到一个更直接的示例来重现,看看它是否可以修复。谢谢。 嗨@Arun,仅供参考,我已经在 Github 上提交了一个问题。希望修复是一个简单的... 【参考方案1】:

(我不能相信伟大的 DT 头脑(Arun)一直在研究这个问题,发现它与 print.data.table 有关。只是在这里为其他 SO 用户关闭循环。) em>

似乎:= data.table 内存问题已在 R 版本 3.2 上得到解决,如下所述: https://github.com/Rdatatable/data.table/issues/1062

[引用 Github 问题 1062 中的 @Arun ...]

已在 R v3.2,IIUC 中修复,此项目来自 NEWS:

当打印被分派给一个方法时,自动打印不再复制对象。

所以其他有这个问题的人应该考虑升级到 R 3.2。

【讨论】:

谢谢@micstr,我完全忘了我在 SO 上发布了这个问题。我在周末对其进行了测试,并确认该问题已在 R3.2 for Linux 中得到解决。 *免责声明:我已切换到在 Linux 中使用 R,因此没有在 Windows 中测试该问题。

以上是关于R - 为啥向数据表添加 1 列几乎会使使用的峰值内存增加一倍?的主要内容,如果未能解决你的问题,请参考以下文章

为啥添加导航控制器会使我的数组消失?

为啥添加 try 块会使程序更快?

为啥使用 DOMDocument 会使网站加载速度变慢?

如何在不缩小r闪亮中的矩阵大小的情况下向输入矩阵添加列?

数据库一列插入多行数据,需要不断循环400次update。

使用 SQL 向 MS Access 中的多个表添加列