这是一个例子:
import numpy as np
randoms = np.random.randint(0, 20, 10000000)
a = randoms.astype(np.int)
b = randoms.astype(np.object)
np.save('d:/dtype=int.npy', a) #39 mb
np.save('d:/dtype=object.npy', b) #19 mb!
您可以看到dtype = object的文件大小只有一半。怎么会?我的印象是,正确定义的numpy dtypes严格优于object dtypes。
答案 0 :(得分:7)
对于非对象dtype,大多数npy文件格式包含数组数据的原始字节的转储。这里每个元素要么是4个或8个字节,这取决于你的NumPy是默认为4个还是8个字节的整数。从文件大小来看,每个元素看起来像4个字节。
对象dtype,大多数npy文件格式由数组的普通pickle组成。对于小整数,例如数组中的小整数,pickle使用K
pickle操作码,长名称BININT1
,"记录"在pickletools
模块中:
I(name='BININT1',
code='K',
arg=uint1,
stack_before=[],
stack_after=[pyint],
proto=1,
doc="""Push a one-byte unsigned integer.
This is a space optimization for pickling very small non-negative ints,
in range(256).
"""),
这需要每个整数两个字节,一个用于K
操作码,一个字节用于无符号整数数据。
请注意,通过使用dtype numpy.int8
或numpy.uint8
存储数组,您可以进一步减小文件大小,每个整数大约1个字节。
答案 1 :(得分:2)
dtype=object
数组在NPY文件中保存为Python pickle。 Python pickle保留对象图内对象的标识;即如果b[i] is b[j]
,那么pickle将第一次序列化b[i]
和b[j]
引用的对象,并在下一次出现时引用它。该引用通常小于序列化对象本身,即使在序列化时对象本身非常小。
Python优化小整数,使得它总是会为-5到256之间的整数重用相同的对象,因此包括所有range(0, 20)
这些是数组中的唯一值。 numpy也可能决定在通过.astype(object)
进行转换时重用实例。
如果您创建了一个数组,其中大部分或全部值都是唯一的,例如浮点uniform(0.0, 1.0, 10000000)
,那么您将得到您期望的相对大小。