如何更快将大型压缩列结构时序数据加载到NumPy数组?
快速加载大型压缩列数据到NumPy数组的方案
核心矛盾拆解
你面临的问题本质是:NumPy数组的搜索性能最优,但npz格式加载速度远不如Parquet;而Parquet通过Pandas加载后转NumPy又存在额外延迟。需要找到兼顾Parquet级加载速度、压缩率,同时能直接映射到NumPy数组的解决方案。
针对性解决方案
1. 利用Parquet内存布局特性,避免全量转换
Pandas加载Parquet后,数值类型的列底层已经是NumPy数组,无需调用to_numpy()做全量复制。直接通过df[col].values或df[col].to_numpy(copy=False)获取原始数组引用,几乎无延迟:
import pandas as pd from fasterparquet import ParquetFile # 仅加载需要的列,进一步提速 pf = ParquetFile("your_data.parquet") df = pf.to_pandas(columns=["timestamp", "value1", "value2"]) # 直接获取底层NumPy数组,无复制开销 timestamp_np = df["timestamp"].values value1_np = df["value1"].to_numpy(copy=False)
这种方式既保留了Parquet的快速加载和高压缩率优势,又直接拿到NumPy数组的底层引用,完全规避转换延迟。
2. 用PyArrow直接读取Parquet到NumPy数组
PyArrow可以跳过Pandas,直接将Parquet列读取为Arrow数组,再零拷贝转换为NumPy数组(兼容数值类型):
import pyarrow.parquet as pq # 读取指定列 table = pq.read_table("your_data.parquet", columns=["timestamp", "value1"]) # 零拷贝转换为NumPy数组 timestamp_np = table["timestamp"].to_numpy() value1_np = table["value1"].to_numpy()
PyArrow的Parquet读取性能与fasterparquet相当,且转换到NumPy的开销极小,适合时序数据的列级读取场景。
3. 优化npz文件的存储与加载
如果必须使用NumPy原生格式,可通过以下方式提速:
- 按列存储+按需加载:避免存储整个二维数组,加载时仅读取需要的列,减少解压量:
import numpy as np # 假设data是shape=(10_000_000, 10)的时序数据数组 np.savez_compressed("data.npz", ts=data[:,0], val1=data[:,1], val2=data[:,2], # 其他列... val9=data[:,9]) # 加载时仅读取需要的列 with np.load("data.npz") as data: ts_np = data["ts"] val1_np = data["val1"]
- 更换高效压缩算法:用Blosc替代
np.savez_compressed默认的ZIP压缩,压缩/解压速度更快:
import blosc import numpy as np # 压缩单列时序数据 col_data = data[:,0] compressed = blosc.compress(col_data, shuffle=blosc.SHUFFLE, cname='zstd') # 保存到文件 with open("ts.blosc", "wb") as f: f.write(compressed) # 加载时直接解压为NumPy数组 with open("ts.blosc", "rb") as f: compressed = f.read() ts_np = np.frombuffer(blosc.decompress(compressed), dtype=col_data.dtype)
4. HDF5的内存映射优化
用h5py直接按列存储为HDF5数据集,加载时可通过内存映射直接访问数据,无需全量加载到内存:
import h5py # 按列写入HDF5,启用gzip压缩 with h5py.File("data.h5", "w") as f: for i in range(data.shape[1]): f.create_dataset(f"col{i}", data=data[:,i], compression="gzip", compression_opts=9) # 加载时直接获取NumPy数组(内存映射,延迟加载) with h5py.File("data.h5", "r") as f: ts_np = f["col0"][:] # 或直接用f["col0"]作为数组使用
适合超大规模时序数据的按需列加载场景。
方案对比总结
| 方案 | 加载速度 | 压缩率 | 直接获取NumPy数组 | 适用场景 |
|---|---|---|---|---|
| Parquet + PyArrow | 极快 | 高 | 是(零拷贝) | 多数时序数据列级读取场景 |
| Parquet + Pandas | 极快 | 高 | 是(无复制) | 需要同时使用Pandas和NumPy时 |
| 优化npz + Blosc | 较快 | 中高 | 是 | 必须用NumPy原生格式的场景 |
| HDF5 + h5py | 快 | 高 | 是(内存映射) | 超大规模数据按需加载列 |
内容的提问来源于stack exchange,提问作者user22943026
相关产品推荐
相关产品推荐

