Xarray库提供了包括数据读写、运算和绘图在内的诸多功能,非常方便灵活,下面会尽可能详细的展示Xarray库的强大美丽,一库通关气象编程。
1 必须知道的基础术语
- DataArray (数据数组): 区别于numpy库中的ndarray,DataArray是具有维度标签信息或其他额外信息的数组,而ndarray仅包含数据。
- Dataset (数据集):可以理解为一个或多个DataArray组成的集合。例如一个.nc文件读进来以后就是一个Dataset。
- Variable (变量):每个DataArray 都包含一个变量。
- Dimension (维度):对于一个气象要素场来说,例如时间,纬度,经度就是这个数据数组的维度。
- Coordinate (坐标):例如在经度维度中,那些经度格点就是它的坐标。
2 DataArray和DataSet
2.1 基础
所以对于一个DataArray来说,它的数据结构应该包含了4个关键属性:
values:数据的值,这里就等同于numpy库中的ndarray了;
dims:每个轴(维度)的名称;
coords:坐标;
attrs:其它属性,例如单位等。
所以我们可以输入这些属性,通过xr.DataArray函数来创建一个DataArray:
1 | import xarray as xr |
如果想偷懒,可以不指定coords和dims,仅输入temperature来快速实现:
1 | temperature_da2 = xr.DataArray(temperature) |
这时候我们再回顾这些关键属性是是么:
1 | print(temperature_da1.values) |
当我们有了DataArray后,便可以轻松的创建Dataset从而来生成.nc文件。
1 | temperature_ds = xr.Dataset({'temperature' : temperature_da1}) |
可以看到先前的DataArray作为一个variable出现在了Dataset里。
在实际使用中,我们读取到的每个数据文件都是一个DataSet,数据文件中的气象要素则是一个DataArray,同样,我们要生成.nc文件时,也要将数据按DataArray<DataSet<.nc的顺序来操作。这部分内容将放在文件读写中一起介绍。
3 文件读写
3.1 netCDF文件读写
先来写一个.nc文件:
1 | import numpy as np |
这样就可以实现从ndarray到.nc文件的输出了,对于需要大量运算的研究来说,建议通过这种方法输出一些中间变量。
接下来读取这个文件:
1 | f = xr.open_dataset("t2m_example.nc") |
3.2 HDF5文件读取
HDF5格式文件的区域与netCDF文件的读取方法类似:
1 | f = xr.open_dataset("file.h5") |
我没有相关的HDF5数据文件,这里就不具体展示了。本质上没有任何区别,读进来以后都是DataSet结构。
如果报错,请查看是否缺少h5netcdf库,可通过:
1 | conda install h5netcdf |
进行安装。
3.3 tif文件读取
tif格式数据常见于各类地理遥感类数据中,如人口,灯光,土地,农作物,地形等等。
读取这类数据需要安装rioxarray库:
1 | pip install rioxarray |
使用方法类似xarray:
1 | import rioxarray |
读取结果为DataArray格式,后续操作即同netCDF数据一致。
3.4 grib文件读取
需要安装cfgrib库:
1 | conda install -c conda-forge cfgrib |
之后通过xarray调用cfgrib引擎即可读取:
1 | f = xr.open_dataset("example.grib", engine="cfgrib") |
后续操作即同netCDF数据一致。
4 索引和筛选数据
索引实际上是Xarray中最重要的部分之一,精通索引可以通过简单的几个Xarray指令便实现用普通代码很复杂的功能(例如闰年2月29号的处理,如何筛选指定位置数据等等)。
4.1 位置索引(下标索引)
使用index来进行索引(我喜欢叫这种索引下标索引,就是用它下标的数字位置来进行索引)的方法与Numpy中是一样的,例如:
1 | print(temperature_da1[:2]) |
数据数组的属性在所有索引操作中都会保留。
4.2 标签索引
Xarray 还支持基于标签的索引,就像 pandas 一样。
1 | print(temperature_da1.loc['1979-01-02','Shanghai']) |
这种操作会广泛应用于气象编程中,例如索引出某个区域的数据,某个时间断的数据等等,这种索引是十分灵活的。
1 | # 以一个NCEP数据为例 |
这里选出了月份在6,7,8月的200hPa风速数据。还可以更复杂:
1 | u200 = f_u['uwnd'].loc[(f_u.time.dt.month.isin([12,1,2]))].loc['1979-12-01':'2021-02-28'] |
这样就选出了1979年到2020年冬季12,1,2月的数据,并且考虑到了冬季数据的跨年问题。
我先前的博客也有写到用索引方式剔除闰年2月29号的方式:
1 | u200 = f_u['uwnd'].loc[~((f_u.time.dt.month==2)&(f_u.time.dt.day==29))] |
~符号表示非,所以这里是选择了非2月29号的全部数据。
因此这种索引方式有很高的上限,取决于对基础编程的掌握水平。
4.3 模糊索引
如果我们想索引某个坐标点的数据,但是这个坐标在数据中又不存在(也可能是显示问题导致数据的小数位显示不全),比如我们索引300hPa数据,但实际上在数据中为300.1hPa,那么一般索引会报错。因此可以使用模糊索引:
1 | da = xr.DataArray([1, 2, 3], [("x", [0, 1, 2])]) |
还可以使用tolerance参数来限制模糊索引的有效距离:
1 | print(da.reindex(x=[1.1, 1.5], method="nearest", tolerance=0.2)) |
4.4 where方法
数据数组也可以使用类似np中的where方法:
1 | da = xr.DataArray(np.arange(16).reshape(4, 4), dims=["x", "y"]) |
使用这个方法可以进行一些索引替换赋值等等的灵活操作。
4.5 气象实例
这里通过一个实例来展示这几种索引方法在实际科研中的常见用法(数据下载):
1 | import xarray as xr |
- 通过下标索引:假设我们想选出前10个时间记录的数据:
1 | f.slp[:10] |
- 通过坐标索引:假设我们想选出1979年,北半球的数据:
1 | f.slp.loc[f.time.dt.year==1979,90:0,:] |
- 模糊索引:我们想选出离37.2°E,44.6°N附近的数据,但是这个坐标点不在数据中存在:
1 | f.slp.sel(lat=44.6,lon=37.2,method='nearest') |
这些索引方法可以组合起来使用:
1 | f.slp.sel(lat=44.6,lon=37.2,method='nearest')[f.time.dt.year==1979] |
所以说Xarray的索引方法十分灵活,兼容性很强,发挥程度完全取决于你的python基础(所以还是那句话,不要想着速成这个速成那个,欠的债都要还的)。