R语言 因子是否比字符更有效地存储在数据表中?

1bqhqjot  于 2023-01-22  发布在  其他
关注(0)|答案(1)|浏览(125)

我想我在什么地方读到过(记不清是在哪里读到的)factors实际上并不比data.table中的字符向量更有效。这是真的吗?我在讨论是否继续使用factors来存储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
4smxwvx5

4smxwvx51#

您可能记得数据。表FAQ 2.17包含:
stringsAsFactors在data.frame中默认为TRUE,而在data.table中默认为FALSE,这是为了提高效率。由于在R中添加了全局字符串缓存,因此字符项是指向单个缓存字符串的指针,转换为factor不再具有性能优势。
(That部分已于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字节。另一方面,字符向量不需要级别,它只有81e6字节。在这两种情况下,全局缓存都以相同的方式存储100万个唯一字符串。在这种情况下,字符列将使用比它是一个因素时更少的RAM。2仔细检查用于计算RAM使用的内存工具是否正确地计算了这一点。

相关问题