排序和解压缩大字节数组的最快方法是什么?

时间:2019-05-02 10:03:08

标签: python python-3.x numpy

我有一个很大的二进制文件,需要将其转换为hdf5文件格式。

我正在使用Python3.6。我的想法是读入文件,对相关信息进行分类,将其解压缩并存储起来。我的信息以以下方式存储:8字节的时间紧随其后的是2字节的能量,然后是2字节的额外信息,然后是时间,……我目前的处理方式如下(我的信息读为一个字节数组,名称为byte_array):

for i in range(0, len(byte_array)+1, 12):

    if i == 0:
        timestamp_bytes = byte_array[i:i+8]
        energy_bytes = byte_array[i+8:i+10]
        extras_bytes = byte_array[i+10:i+12]
    else:
        timestamp_bytes += byte_array[i:i+8]
        energy_bytes += byte_array[i+8:i+10]
        extras_bytes += byte_array[i+10:i+12]


timestamp_array = np.ndarray((len(timestamp_bytes)//8,), '<Q',timestamp_bytes)
energy_array = np.ndarray((len(energy_bytes) // 2,), '<h', energy_bytes)
extras_array = np.ndarray((len(timestamp_bytes) // 8,), '<H', extras_bytes)

我认为有一个更快的方法可以执行此操作,也许可以避免遍历整个过程。我的文件最大为15GB,因此每一点改进都会有很大帮助。

3 个答案:

答案 0 :(得分:1)

您应该能够告诉NumPy将数据解释为结构化数组并提取字段:

as_structured = numpy.ndarray(shape=(len(byte_array)//12,),
                              dtype='<Q, <h, <H',
                              buffer=byte_array)
timestamps = as_structured['f0']
energies = as_structured['f1']
extras = as_structured['f2']

这将产生由输入字节数组支持的三个数组。创建这些数组实际上应该是即时的,但是我不能保证与它们​​的合作会很快-我认为NumPy可能需要执行一些隐式复制来处理这些数组的对齐问题。可能(我不知道)是,首先使用.copy()明确地自己复制它们可能会加快速度。

答案 1 :(得分:0)

您可以将numpy.frombuffer与自定义数据类型一起使用:

import struct
import random

import numpy as np


data = [
    (random.randint(0, 255**8), random.randint(0, 255*255), random.randint(0, 255*255))
    for _ in range(20)
    ]

Bytes = b''.join(struct.pack('<Q2H', *row) for row in data)
dtype = np.dtype([('time', np.uint64), 
                  ('energy', np.uint16), # you may need to change that to `np.int16`, if energy can be negative
                  ('extras', np.uint16)])

original = np.array(data, dtype=np.uint64)
result = np.frombuffer(Bytes, dtype)

print((result['time'] == original[:, 0]).all())
print((result['energy'] == original[:, 1]).all())
print((result['extras'] == original[:, 2]).all())

print(result)

示例输出:

True
True
True
[(6048800706604665320, 52635, 291) (8427097887613035313, 15520, 4976)
 (3250665110135380002, 44078, 63748) (17867295175506485743, 53323, 293)
 (7840430102298790024, 38161, 27601) (15927595121394361471, 47152, 40296)
 (8882783920163363834, 3480, 46666) (15102082728995819558, 25348, 3492)
 (14964201209703818097, 60557, 4445) (11285466269736808083, 64496, 52086)
 (6776526382025956941, 63096, 57267) (5265981349217761773, 19503, 32500)
 (16839331389597634577, 49067, 46000) (16893396755393998689, 31922, 14228)
 (15428810261434211689, 32003, 61458) (5502680334984414629, 59013, 42330)
 (6325789410021178213, 25515, 49850) (6328332306678721373, 59019, 64106)
 (3222979511295721944, 26445, 37703) (4490370317582410310, 52413, 25364)]

答案 2 :(得分:0)

我不是numpy的专家,但这是我的5美分: 您有很多数据,可能不仅仅是RAM。 这指向了最简单的解决方案-不要尝试在程序中容纳所有数据。 当您将文件读取到变量中时-X GB被读取到RAM中。如果超过可用的RAM,则交换由您的OS完成。交换会减慢您的速度,因为不仅您有磁盘操作可从源文件读取,而且现在您还写入磁盘以将RAM内容转储到交换文件中。 代替编写脚本,以便脚本在必要时使用输入文件的某些部分(对于您而言,无论如何都应阅读文件,并且不要向后或向前跳)。

尝试以memory mapped data structure的形式打开输入文件(请注意Unix和Windows环境在用法上的差异)

然后,您可以一次执行简单的read([n])个字节,并将其附加到数组中。 幕后的数据将被读取到RAM page by page as needed中,并且不会超出可用内存,也为阵列留下了更大的增长空间。

还要考虑这样一个事实,即结果数组也可能超出RAM,这将导致与读取大文件类似的速度降低。