R似乎每个整数需要四个字节的存储空间,即使对于小整数也是如此:
> object.size(rep(1L, 10000))
40040 bytes
而且,甚至是因素:
> object.size(factor(rep(1L, 10000)))
40456 bytes
我认为,特别是在后一种情况下,这可以更好地处理。有没有一种解决方案可以帮助我将这种情况的存储要求降低到每行八位甚至两位?也许是一种在内部使用raw
类型进行存储的解决方案,但其行为类似于正常因素。 bit
包为比特提供了这个功能,但我没有找到任何类似因素。
我的数据框只有几百万行消耗千兆字节,这是一个巨大的浪费内存和运行时间(!)。压缩将减少所需的磁盘空间,但同样会以运行时为代价。
相关:
答案 0 :(得分:6)
由于您提到raw
(假设您的因子级别少于256) - 如果内存是您的瓶颈且CPU时间不是,那么可以执行必备转换操作。例如:
f = factor(rep(1L, 1e5))
object.size(f)
# 400456 bytes
f.raw = as.raw(f)
object.size(f.raw)
#100040 bytes
# to go back:
identical(as.factor(as.integer(f.raw)), f)
#[1] TRUE
你也可以单独保存因子水平并恢复它们,如果那是你感兴趣的事情,但就分组和所有这些而言你可以用raw
完成所有这些并且永远不会回到因素(演示除外)。
如果您遇到使用此方法的特定用例,请发布,否则我认为这应该可以正常使用。
以下是byte.factor
课程的起点:
byte.factor = function(f) {
res = as.raw(f)
attr(res, "levels") <- levels(f)
attr(res, "class") <- "byte.factor"
res
}
as.factor.byte.factor = function(b) {
factor(attributes(b)$levels[as.integer(b)], attributes(b)$levels)
}
所以你可以这样做:
f = factor(c('a','b'), letters)
f
#[1] a b
#Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
b = byte.factor(f)
b
#[1] 01 02
#attr(,"levels")
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
#[20] "t" "u" "v" "w" "x" "y" "z"
#attr(,"class")
#[1] "byte.factor"
as.factor.byte.factor(b)
#[1] a b
#Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
如果您想data.table
通用,只需添加要添加的任何功能,请查看rbind.data.frame
覆盖as.factor
的方式。应该都很简单。
答案 1 :(得分:3)
另一个解决方案是使用ff
。 ff
支持以下vmodes / types(请参阅?vmode
):
‘boolean’ ‘as.boolean’ 1 bit logical without NA
‘logical’ ‘as.logical’ 2 bit logical with NA
‘quad’ ‘as.quad’ 2 bit unsigned integer without NA
‘nibble’ ‘as.nibble’ 4 bit unsigned integer without NA
‘byte’ ‘as.byte’ 8 bit signed integer with NA
‘ubyte’ ‘as.ubyte’ 8 bit unsigned integer without NA
‘short’ ‘as.short’ 16 bit signed integer with NA
‘ushort’ ‘as.ushort’ 16 bit unsigned integer without NA
‘integer’ ‘as.integer’ 32 bit signed integer with NA
‘single’ ‘as.single’ 32 bit float
‘double’ ‘as.double’ 64 bit float
‘complex’ ‘as.complex’ 2x64 bit float
‘raw’ ‘as.raw’ 8 bit unsigned char
‘character’ ‘as.character’ character
例如:
library(ff)
v <- ff(as.factor(sample(letters[1:4], 10000, replace=TRUE)), vmode="byte",
levels=letters[1:4])
每个元素只使用一个字节。另一个优点/缺点是,当数据太大而无法存储到内存中时,它会自动存储在磁盘上(这当然会影响性能)。
但是,无论您使用何种解决方案,都可能会降低性能。 R内部使用整数作为因子,因此在调用任何R方法之前,必须将数据从紧凑存储转换为R的整数,这将花费成本。除非,您只使用专门为紧凑存储类型编写的方法(这些可能必须用c / c ++ / ...编写)。
答案 2 :(得分:2)
在盒子外面一点点,但是游程编码可能适用于少量级别的长因子,前提是元素在某种程度上是有序的; IRanges
中的Bioconductor包可以支持此功能rle = Rle(factor("A"), 1000000)
df = DataFrame(rle=rle)
和
> object.size(rle)
1528 bytes
DataFrame
和Rle
支持所有标准操作,例如,子集化,添加Rle。当然,节省的尺寸主要取决于维护排序顺序。