首页 > 解决方案 > Python:如何使用 xarray 编写大型 netcdf

问题描述

我正在使用xr.mfdataset. 许多文件中有 16GB 的数据。

import xarray as xr
from datetime import datetime
from pathlib import Path

from dask.diagnostics import ProgressBar
def add_time_dim(xda: xr.Dataset) -> xr.Dataset:
    # https://stackoverflow.com/a/65416801/9940782 
    xda = xda.expand_dims(time = [datetime.now()])
    return xda

raw_folder = data_dir / "raw/modis_ndvi_1000"
    
files = [f for f in raw_folder.glob("*.nc")]
data = xr.open_mfdataset(files, preprocess=add_time_dim)
data
<xarray.Dataset>
Dimensions:     (time: 647, lat: 5600, lon: 4480)
Coordinates:
  * time        (time) datetime64[ns] 2004-04-30 2005-10-10 ... 2018-10-31
  * lat         (lat) float64 -19.99 -19.98 -19.97 -19.96 ... 29.98 29.99 30.0
  * lon         (lon) float64 20.0 20.01 20.02 20.03 ... 59.96 59.97 59.98 59.99
Data variables:
    modis_ndvi  (time, lat, lon) float32 dask.array<chunksize=(1, 5600, 4480), meta=np.ndarray>

选择我感兴趣的区域后,我将数据集的大小减半(~8GB)

<xarray.Dataset>
Dimensions:     (time: 647, lat: 1255, lon: 983)
Coordinates:
  * time        (time) datetime64[ns] 2004-04-30 2005-10-10 ... 2018-10-31
  * lat         (lat) float64 -5.196 -5.187 -5.179 -5.17 ... 5.982 5.991 6.0
  * lon         (lon) float64 33.51 33.52 33.53 33.54 ... 42.26 42.27 42.28
Data variables:
    modis_ndvi  (time, lat, lon) float32 dask.array<chunksize=(1, 1255, 983), meta=np.ndarray>

## 每次我尝试保存数据时,过程都是Killed. 如何将这个大文件写入 netcdf?

out_folder = data_dir / "interim/modis_ndvi_1000_preprocessed"
out_folder.mkdir(exist_ok=True)
out_file = out_folder / f"modis_ndvi_1000_{subset_str}.nc"

data.to_netcdf(out_file, compute=False)
with ProgressBar():
    print(f"Writing to {out_file}")
    data.compute()


Killed

我需要做什么?如何应对这个庞大的数据集,如何将其并行写入磁盘?

该进程被杀死,因为所有可用内存都用完了(观看时可以看到htop

htop 显示内存使用情况

标签: pythondaskpython-xarray

解决方案


to_netcdf(compute=False)返回一个dask.delayed.Delayed对象。您应该将其存储为变量并计算它而不是计算数组:

write_job = data.to_netcdf(out_file, compute=False)
with ProgressBar():
    print(f"Writing to {out_file}")
    write_job.compute()

您拥有的代码会启动延迟的写入作业,然后尝试将整个数组data放入内存。

也就是说,zarr更适合并行写入。即使使用分布式任务集群支持的数组,to_netcdf 也会将数组带到本地线程(以块的形式,但仍然如此)以写入主线程中的 netcdf。使用 zarr 写入调度写入,然后工作人员并行写入存储。如果您在网络或云文件系统上,这可能会产生巨大的影响。如果您能够使用 zarr,我会检查该格式!


推荐阅读