如何使这个 R data.table 代码更节省内存?
Posted
技术标签:
【中文标题】如何使这个 R data.table 代码更节省内存?【英文标题】:How to make this R data.table code more memory-efficient? 【发布时间】:2015-03-12 23:21:37 【问题描述】:我有两个真实的data.table
代码示例,它们可以正常工作,但似乎消耗的内存比我预期的要多,我非常感谢有关如何使这段代码更节省内存的想法。
A = data.table(a=c(rep(1,5),rep(2,5)), b1=2:11, b2=22:31, c=c(1,2,1,2,1,2,1,2,1,2))
# Example 1:
# Pick the column name (b1 or b2) based on the value in column a
# and assign the value from <b1 or b2> by reference to column res
setkey(A, a, c)
A[, res:=get(paste0("b", a)), by=c("a", "c")]
# Example 2:
# Group the values of A by key, saving the following:
# 1) number of values in column res that meet some condition
# 2) the minimum value of column a
setkey(A, c)
z = A[, list(length(.I[res>5]), min(res)), by=c]
我使用lineprof
使用更大的真实数据对它们进行了测试,在整个使用data.tables
的代码中它们是异常值。
# This is more like the real size of the data I'm dealing with
A = data.table(a=c(rep(1,5e6),rep(2,5e6)),
b1=1:5e6, b2=(5e6+1):10e6,
c=round(runif(1e7, min=1, max=2)))
任何建议将不胜感激!
【问题讨论】:
感谢@David 的编辑 - 很好发现! 我认为第二个问题你可以做A[, .(sum(res>5), min(res)), by=c]
您也不应该在每次迭代中调用 paste,您可以使用 do.call
调用一次,然后仅在 get
上迭代,例如 A[, temp := do.call(paste0, list("b", a))][, res := get(temp), .(a, c)]
虽然 mnel 二进制搜索会更多高效。
@mnels 二进制连接不是更有效吗?我不明白。
您的data.table
版本是什么?当前开发1.9.5
中修复了一些不需要的泄漏(来自 1.9.2/1.9.4)。
【参考方案1】:
如果示例 1 只是使用 by = list(a,c)
逐行处理,那么 get 可以工作,那么
setkey(A,a)
A[.(1), res := b1]
A[.(2), res:= b2]
应该更有效率
例如 2,通过 res 排序/键控也可以提高性能
setkey(A, c,res)
z = A[, list(length(.I[res>5]),(res[1])), by=c]
【讨论】:
谢谢!实际上,我尝试按照您在第一个示例中的建议进行操作,并且花费了绝对的时间(我在现实生活中获得了 75 个级别)。现在将尝试第二个示例! 你有 75b
cols 吗?如果是,需要多长时间:A[.(a=1:75), res := get(paste0("b", i.a)), by=.EACHI]
?
新闻中记录了 i.a 语法。 i.a 组件表示您想从 i 参数而不是 j 的范围中获取“a”。 (@arun 的建议很棒)
我写了一个愉快的回复,但后来注意到在我的例子中,由于某种原因,这个示例未能遍历a
的级别......以上是关于如何使这个 R data.table 代码更节省内存?的主要内容,如果未能解决你的问题,请参考以下文章
R语言data.table导入数据实战:data.table进行多表数据连接(mergejoin)内连接左连接外连接