如何在转换为numpy数组/pandas DataFrame前高效过滤字节流?
问题描述
我需要在将数据转换为NumPy数组或Pandas DataFrame前,高效过滤掉不需要的字段。数据是以单个字符串缓冲区(每条记录对应一个缓冲区)传递给程序的,目前我用np.frombuffer在收集所有记录后构建数组。
问题在于单条记录可能包含数千个字段,但有时我只需要其中一小部分:
- 如果先拼接所有记录再构建完整数组,再提取需要的列,会浪费大量内存;
- 如果逐条切片记录再重新拼接,中间步骤又会让过滤比直接读取全部数据更慢。
当前无过滤流程
# 假设此处有函数逐条获取记录并添加到'data'中 data = [b'\x00\x00\x00\x00\x00\x00\xf0?one \x00\x00\x00\x00\x00\x00Y@', b'\x00\x00\x00\x00\x00\x00\x00@two \x00\x00\x00\x00\x00\x00i@', b'\x00\x00\x00\x00\x00\x00\x08@three \x00\x00\x00\x00\x00\xc0r@', b'\x00\x00\x00\x00\x00\x00\x10@four \x00\x00\x00\x00\x00\x00y@'] final_data = b''.join(data) arr = np.frombuffer(final_data, dtype=struct_dtypes) df = pd.DataFrame(arr) # 生成的DataFrame n1 ch n2 0 1.0 one 100.0 1 2.0 two 200.0 2 3.0 three 300.0 3 4.0 four 400.0
当前低效过滤方案
final_data = b''.join(b''.join(buffer[offset: offset + 8] for offset in [0, 16]) for buffer in data) struct_dtypes = np.dtype([('n1', 'd'), ('n2', 'd')]) arr = np.frombuffer(final_data, dtype=struct_dtypes) df = pd.DataFrame(arr) # 生成的DataFrame n1 n2 0 1.0 100.0 1 2.0 200.0 2 3.0 300.0 3 4.0 400.0
这种逐条切片再拼接的方式效率很低,请问有没有合适的方法可以只读取字符串缓冲区中需要的部分?
解决方案
直接通过自定义NumPy dtype的offsets和itemsize参数,让np.frombuffer直接跳过不需要的字段,无需提前切片或拼接数据:
实现代码
# 定义只包含需要字段的dtype,指定每个字段的偏移量和单条记录总长度 struct_dtypes = np.dtype({ 'names': ['n1', 'ch'], 'formats': ['d', '8V'], # '8V'表示8字节的原始数据(对应示例中的字符串字段) 'offsets': [0, 8], # 每个字段在单条记录中的起始偏移 'itemsize': 24 # 单条记录的总字节长度(对应原始每条buffer的长度) }) final_data = b''.join(data) arr = np.frombuffer(final_data, dtype=struct_dtypes)
核心原理
- 指定字段偏移:通过
offsets参数定义需要读取的字段在单条记录中的起始字节位置,NumPy会直接定位读取,自动跳过不需要的字段; - 固定记录长度:
itemsize参数设置单条记录的总字节数,确保np.frombuffer能正确将连续的二进制数据分割为独立记录; - 零数据修改:无需对原始二进制缓冲区做切片、拼接操作,直接基于完整二进制数据按需读取,最大化内存利用率和处理速度。
使用已采纳方案后的更新
struct_dtypes = np.dtype({'names': ['n1', 'ch'], 'formats': ['d', '8V'], 'offsets': [0, 8], 'itemsize': 24}) final_data = b''.join(data) arr = np.frombuffer(final_data, dtype=struct_dtypes)
内容的提问来源于stack exchange,提问作者StevenS
相关产品推荐
相关产品推荐

