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 列几乎会使使用的峰值内存增加一倍?的主要内容,如果未能解决你的问题,请参考以下文章