因子在 data.table 中的存储效率是不是比字符更有效?
Posted
技术标签:
【中文标题】因子在 data.table 中的存储效率是不是比字符更有效?【英文标题】:Are factors stored more efficiently in data.table than characters?因子在 data.table 中的存储效率是否比字符更有效? 【发布时间】:2016-04-24 02:29:33 【问题描述】:虽然我在某个地方(不记得在哪里)读到过这些因素实际上并不比 data.table 中的字符向量更有效。这是真的?我在争论是否继续使用因子将各种向量存储在 data.table 中。 object.size
的近似测试似乎表明并非如此。
chars <- data.table(a = sample(letters, 1e5, TRUE)) # chars (not really)
string <- data.table(a = sample(state.name, 1e5, TRUE)) # strings
fact <- data.table(a = factor(sample(letters, 1e5, TRUE))) # factor
int <- data.table(a = sample(1:26, 1e5, TRUE)) # int
mbs <- function(...)
ns <- sapply(match.call(expand.dots=TRUE)[-1L], deparse)
vals <- mget(ns, .GlobalEnv)
cat('Sizes:\n',
paste('\t', ns, ':', round(sapply(vals, object.size)/1024/1024, 3), 'MB\n'))
## Get approximate sizes?
mbs(chars, string, fact, int)
# Sizes:
# chars : 0.765 MB
# string : 0.766 MB
# fact : 0.384 MB
# int : 0.382 MB
【问题讨论】:
其他阅读此问题的人可能对 R 的一般行为感兴趣;根据 Hadley Wickham 的说法,“R 有一个全局字符串池。这意味着每个唯一的字符串只存储在一个位置,因此字符向量占用的内存比您预期的要少。”见adv-r.had.co.nz/memory.html。 【参考方案1】:您可能还记得 data.table FAQ 2.17,其中包含:
stringsAsFactors 在 data.frame 中默认为 TRUE,但在 data.table 中为 FALSE,以提高效率。由于在 R 中添加了全局字符串缓存,字符项是指向单个缓存字符串的指针,转换为因子不再有性能优势。
(该部分已于 2012 年 7 月添加到 v1.8.2 的常见问题解答中。)
在堆叠(rbindlist)之类的任务中,使用字符而不是因子有很大帮助。由于两个字符向量的 c()
只是串联,而两个因子列的 c()
需要遍历和合并两个因子级别,这更难编码并且执行时间更长。
您注意到的是 64 位机器上 RAM 消耗的差异。因子存储为级别中项目的integer
向量查找。 integer
类型是 32 位的,即使在 64 位平台上也是如此。但是指针(character
向量是什么)在 64 位机器上是 64 位的。因此,在 64 位机器上,字符列将使用两倍于因子列的 RAM。 32位没有区别。但是,通常这种成本会被字符向量上可能的更简单和更快的指令所抵消。 [旁白:由于因子是integer
,它们不能包含超过 20 亿个唯一字符串。 character
列没有这个限制。]
这取决于您在做什么,但操作已针对 data.table 中的 character
进行了优化,因此我们建议您这样做。基本上它节省了一个跃点(到关卡),我们可以通过比较指针值来比较不同表中的两个字符列,而根本不跳转,甚至到全局缓存。
这也取决于列的基数。假设该列有 100 万行并包含 100 万个唯一字符串。将其存储为因子将需要 100 万个字符向量用于关卡,再加上 100 万个整数向量指向关卡的元素。那是 (4+8)*1e6 字节。另一方面,字符向量不需要级别,它只是 8*1e6 字节。在这两种情况下,全局缓存都以相同的方式存储 100 万个唯一字符串,因此无论如何都会发生这种情况。在这种情况下,字符列将比它是一个因素使用更少的 RAM。仔细检查用于计算 RAM 使用量的内存工具是否正确计算。
【讨论】:
@jenesaisquoi cran.r-project.org/doc/manuals/r-devel/… 然后在源代码中搜索 mkChar()。以上是关于因子在 data.table 中的存储效率是不是比字符更有效?的主要内容,如果未能解决你的问题,请参考以下文章