我正在尝试减少某些数据集的内存占用量,在这些数据集中我每列具有少量因素(重复多次)。有更好的方法将其最小化吗?为了进行比较,这是我仅使用因素得出的结果:
library(pryr)
N <- 10 * 8
M <- 10
初始数据:
test <- data.frame(A = c(rep(strrep("A", M), N), rep(strrep("B", N), N)))
object_size(test)
# 1.95 kB
使用因素:
test2 <- as.factor(test$A)
object_size(test2)
# 1.33 kB
在旁边:我很天真地以为他们用数字替换了字符串,并且很高兴看到test2
小于test3
。谁能指出一些有关如何优化因子表示的材料?
test3 <- data.frame(A = c(rep("1", N), rep("2", N)))
object_size(test3)
# 1.82 kB
答案 0 :(得分:8)
恐怕差异很小。
原理很简单:您将只存储2和160个整数(仅4个字节),而不是(在您的示例中)160个字符串。
除了R种内部存储字符的方式相同。
每种现代语言都支持(实际上)无限长度的字符串。这就带来了一个问题,您不能将字符串的向量(或数组)存储为一个连续的块,因为任何元素都可以重置为任意长度。因此,如果为一个元素分配了另一个值,而这个值恰好更长一些,这意味着必须对数组的其余部分进行移位。否则操作系统/语言应为每个字符串保留大量空间。
因此,将字符串存储在内存中方便的任何位置,并将数组(或R中的向量)作为 pointers 的块存储到值实际所在的位置。
在R的早期,即使实际值相同,每个指针也指向内存中的另一个位置。因此,在您的示例中,有160个指针指向160个存储位置。但这已经改变了,如今已实现为指向2个内存位置的160个指针。
可能会有一些细微的差异,主要是因为一个因子通常只能支持2 ^ 31-1级别,这意味着32位整数足以存储它,而字符大多使用64位指针。再说一次,因素的开销更大。
通常,如果您确实有很大比例的重复项,那么使用 在使用因素方面可能会有一些优势,但是如果不是这样,甚至可能会损害您的内存使用率。
您提供的示例不起作用,因为您正在将data.frame与一个因子(而不是裸字符)进行比较。
甚至更强大:当重现您的示例时,只有将stringsAsFactors
设置为FALSE
时,您才能得到结果,因此您正在将一个因数与data.frame中的一个因数进行比较。
否则,比较结果将得出较小的不同:字符1568,因数1328。
而且只有当您具有很多相同的值时,这才起作用,如果您看一下,您会发现该系数可能更大:
> object.size(factor(sample(letters)))
2224 bytes
> object.size(sample(letters))
1712 bytes
因此,通常来说,除了在您实际要存储的内容中使用常识之外,没有任何真正的方法可以压缩数据同时保持易于使用。
答案 1 :(得分:2)
对于您的问题,我没有直接答案,但这是Hadley Wickham的"Advanced R"书中的一些信息:
因素
属性的一个重要用途是定义因素。一个因素 是一个只能包含预定义值的向量,用于 存储分类数据。因素建立在整数向量之上 使用两个属性:类“ factor”,使它们的行为 与常规整数向量和水平不同 定义允许值的集合。
也:
“尽管因素看起来(并且经常表现得像字符向量,但它们 实际上是整数。将它们像字符串一样对待时要小心。 一些字符串方法(例如gsub()和grepl())会强制转换为 字符串,而其他字符串(例如nchar())将抛出错误,并且仍然 其他(如c())将使用基础整数值。为了这 原因,通常最好是将因子明确转换为字符 向量,如果您需要类似字符串的行为。在早期的R版本中, 使用因素代替性格具有记忆优势 向量,但情况已不再如此。”
答案 2 :(得分:1)
R中有一个名为fst
(Lightning Fast Serialization of Data Frames for R)
的软件包,您可以在其中为数据帧创建压缩的fst
对象。详细说明请参见{{3 }},但我将简要说明如何使用它以及fst
对象占用多少空间。首先,让您的test
数据框更大一些,如下所示:
library(pryr)
N <- 1000 * 8
M <- 100
test <- data.frame(A = c(rep(strrep("A", M), N), rep(strrep("B", N), N)))
object_size(test)
# 73.3 kB
现在,让我们将该数据帧转换为fst
对象,如下所示:
install.packages("fst") #install the package
library(fst) #load the package
path <- paste0(tempfile(), ".fst") #create a temporary '.fst' file
write_fst(test, path) #write the dataframe into the '.fst' file
test2 <- fst(path) #load the data as an fst object
object_size(test2)
# 2.14 kB
创建的.fst
文件的磁盘空间为434 bytes
。您可以将test2
作为普通数据帧处理(据我尝试)。
希望这会有所帮助。