NumPy:3字节,6字节类型(又名uint24,uint48)

Ili*_* K. 5 python numpy bigdata

NumPy似乎缺乏对3字节和6字节类型的内置支持,aka uint24uint48.我有一个使用这些类型的大型数据集,并希望将其提供给numpy.我目前做什么(对于uint24):

import numpy as np
dt = np.dtype([('head', '<u2'), ('data', '<u2', (3,))])
# I would like to be able to write
#  dt = np.dtype([('head', '<u2'), ('data', '<u3', (2,))])
#  dt = np.dtype([('head', '<u2'), ('data', '<u6')])
a = np.memmap("filename", mode='r', dtype=dt)
# convert 3 x 2byte data to 2 x 3byte
# w1 is LSB, w3 is MSB
w1, w2, w3 = a['data'].swapaxes(0,1)
a2 = np.ndarray((2,a.size), dtype='u4')
# 3 LSB
a2[0] = w2 % 256
a2[0] <<= 16
a2[0] += w1
# 3 MSB
a2[1] = w3
a2[1] <<=8
a2[1] += w2 >> 8
# now a2 contains "uint24" matrix
Run Code Online (Sandbox Code Playgroud)

虽然它适用于100MB输入,但它看起来效率低(想想100s GB的数据).有更有效的方法吗?例如,创建一种特殊类型的只读视图来屏蔽部分数据将是有用的(类型为"uint64,两个MSB始终为零"类型).我只需要对数据进行只读访问.

eca*_*mur 6

我不相信有办法做你所要求的(它需要不对齐的访问,这在一些架构上效率非常低).从文件读取和存储任意字节长度整数的解决方案可能更有效地将数据传输到进程内数组:

a = np.memmap("filename", mode='r', dtype=np.dtype('>u1'))
e = np.zeros(a.size / 6, np.dtype('>u8'))
for i in range(3):
    e.view(dtype='>u2')[i + 1::4] = a.view(dtype='>u2')[i::3]
Run Code Online (Sandbox Code Playgroud)

您可以使用strides构造函数参数获得未对齐的访问权限:

e = np.ndarray((a.size - 2) // 6, np.dtype('<u8'), buf, strides=(6,))
Run Code Online (Sandbox Code Playgroud)

然而,有了这个,每个元素将与下一个元素重叠,所以要实际使用它,你必须屏蔽掉访问时的高字节.