前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >xarray系列 | 基于xarray和dask并行写多个netCDF文件

xarray系列 | 基于xarray和dask并行写多个netCDF文件

作者头像
bugsuse
发布2022-09-23 14:27:13
2.6K0
发布2022-09-23 14:27:13
举报
文章被收录于专栏:气象杂货铺

xarray的典型计算工作流程通常包括:

  • 使用xr.open_mfdatasetxr.open_dataset(chunks=...) 读取单个或多个文件到 Dataset
  • 对读取的输入对象执行一系列变换操作
  • 使用to_netcdf方法保存结果

上述步骤通常会产生很大的nc文件(>10G),尤其是在处理大量数据时。最近在处理卫星数据时,最终生成的文件甚至超过了50G,有些甚至超过了100G。而目前xarray对于nc格式的大文件存储让人头疼。在存储这些大文件时耗时很长,甚至可能会导致程序挂起。

为了避免上述问题,可以利用xr.save_mfdataset,可以同时存储多个dataset对象。关于此函数的说明可查看官方文档。

首先导入所需要的库:

代码语言:javascript
复制
import xarray as xr
import numpy as np
from distributed import Client, performance_report

然后创建Client对象,构建本地cluster:

代码语言:javascript
复制
client = Client()

dask创建的多进程cluster

不同的机器和参数设置上述信息会存在差异

然后加载数据集:

代码语言:javascript
复制
ds = xr.tutorial.open_dataset('rasm', chunks={'time': 12})

此数据集为xarray官方提供的示例数据。这里设置的 time 维度的块大小为12。然后,对上述数据集执行相关计算操作:

代码语言:javascript
复制
result = np.sqrt(np.sin(ds) ** 2 + np.cos(ds) ** 2)

计算过程使用了 dask,可以执行如下语句查看计算图:

代码语言:javascript
复制
result.Tair.data.visualize()

dask计算图,点击可看大图

计算完成后,为了并行存储nc文件,需要将上述结果分割为多个对象:

创建分割函数将上述dataset对象分割为多个子dataset对象:

代码语言:javascript
复制
import itertools
def split_by_chunks(dataset):
    chunk_slices = {}
    for dim, chunks in dataset.chunks.items():
        slices = []
        start = 0
        for chunk in chunks:
            if start >= dataset.sizes[dim]:
                break
            stop = start + chunk
            slices.append(slice(start, stop))
            start = stop
        chunk_slices[dim] = slices
    for slices in itertools.product(*chunk_slices.values()):
        selection = dict(zip(chunk_slices.keys(), slices))
        yield dataset[selection]

分割对象:

代码语言:javascript
复制
datasets = list(split_by_chunks(result))

返回结果中的每一项对应的是xarray的dataset对象的每一个切片。

然后需要一个函数为分割后的每一个dataset对象生成路径:

代码语言:javascript
复制
def create_filepath(ds, prefix='filename', root_path="."):
    """
    Generate a filepath when given an xarray dataset
    """
    start = ds.time.data[0].strftime("%Y-%m-%d")
    end = ds.time.data[-1].strftime("%Y-%m-%d")
    filepath = f'{root_path}/{prefix}_{start}_{end}.nc'
    return filepath

先在一个dataset对象上执行上述函数,测试函数是否能正常运行:

代码语言:javascript
复制
create_filepath(datasets[1])

下一步就是为每一个dataset对象创建一个路径,用于保存数据:

代码语言:javascript
复制
paths = [create_filepath(ds) for ds in datasets]

最后,就可以利用xr.sace_mfdataset函数并行存储nc文件了:

代码语言:javascript
复制
xr.save_mfdataset(datasets=datasets, paths=paths)

保存完数据之后,可以检查一下并行存储的结果和单独存储的结果是否一致。

读取存储的数据:

代码语言:javascript
复制
new_ds = xr.open_mfdataset(paths, combine='by_coords')

然后和上述计算的结果进行对比:

代码语言:javascript
复制
try:
    xr.testing.assert_identical(result, new_ds)
except AssertionError:
    print('The datasets are not identical!')
else:
    print('The datasets are identical!')

netCDF可是的写操作一直是xarray的痛点,尤其是在并行写和增量写文件方面。之前也介绍过另一种文件格式 Zarr真的能替代NetCDF4和HDF5吗,在文件并行写和增量写方面非常友好,尤其是涉及到大文件时。

目前新版本的netCDF库也逐渐支持zarr格式,但还没测试过效果如何。如果不是一定要netCDF格式的话,可以尝试使用zarr格式。

后话:虽然本文使用了dask,但是涉及到dask的内容比较少。最近在处理数据时用到了dask,后面有时间可能会更一些dask相关的推文,比如数据并行处理。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 气象汇 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档