我一直在对如何使用 netCDF 或 Zarr 文件格式以及任一文件格式提供的所有不同编码选项使用 xarray 存储 N 维数组进行基准测试。 Zarr 在我的数据和系统上似乎总体上优于 netCDF,但我发现生成的文件有一些令人惊讶的地方。
下面的 MWE 生成 16793600 字节的
xarray.Dataset
import numpy as np
import xarray as xr
import zarr
# Versions (Python 3.11.6)
print(np.__version__) # 1.26.0
print(xr.__version__) # 2023.10.1
print(zarr.__version__) # 2.16.1
rng = np.random.default_rng(0)
t = 10
ds = xr.Dataset(
data_vars=dict(
A=(["y", "x"], rng.normal(size=(2**t,2**t))),
B=(["y", "x"], rng.normal(size=(2**t,2**t))),
),
coords=dict(
x=(["x"], np.linspace(0, 1, 2**t)),
y=(["y"], np.linspace(0, 1, 2**t)),
),
)
print(f'{ds.nbytes}') # 16793600
# To netCDF, using different engines
ds.to_netcdf('file1.nc', engine='netcdf4', encoding=None)
ds.to_netcdf('file2.nc', engine='scipy', encoding=None)
ds.to_netcdf('file3.nc', engine='h5netcdf', encoding=None)
# To Zarr
ds.to_zarr('file.zarr', encoding=None)
但是生成的文件是
$ du -bs file*
16801792 file1.nc
16793952 file2.nc
16801792 file3.nc
16017234 file.zarr
也就是说,Zarr 文件更小,存储时减少了近 800 kB。编码设置为
None
,我将其理解为“不使用压缩”。这看起来差异很小,但我正在使用 38 GB xarray.Dataset
。使用相同的方法,其中 encoding=None
,netCDF 使用 netcdf4
或 h5netcdf
引擎得到 38 GB(scipy
由于某种原因失败),而 Zarrs 只有 16 GB,一半!
如果没有指定编码,这怎么可能? Zarr(或 xarray)在做什么?如果使用任何压缩,我可以避免它吗?我注意到保存和读取这些大型 Zarr 文件,虽然花费的时间更少,但它们比 netCDF 对应文件使用更多的内存。
保存后,您应该仔细检查 netcdf4 和 zarr 数据的编码。
ncdump -hs
将显示netcdf编码,您可以直接打开zarr数组元数据JSON文件。根据您的描述,我怀疑这两种格式都使用了一些默认压缩。
如果您想强制 Zarr 忽略其默认压缩,您需要为每个数组设置
compressor
编码参数 None
:
store = {}
ds.to_zarr(store, encoding={"A": {"compressor": None}, "B": {"compressor": None}})
json.loads(store['A/.zarray'])
# yields
{'chunks': [256, 256],
'compressor': None,
'dtype': '<f8',
'fill_value': 'NaN',
'filters': None,
'order': 'C',
'shape': [1024, 1024],
'zarr_format': 2}'