xarray概述

时间:2024-11-21 07:59:59

xarray概述

    • 创建DataArray
    • 索引(Indexing)
    • 属性(Attributes)
    • 计算(Computation)
    • GroupBy
    • 绘图(Plotting)
    • pandas
    • Datasets
    • 读写netCDF文件

以下是可以使用对象的事例。更多详细信息可以参阅剩余其他文档。

首先,导入 numpy, pandas 和 xarray,并使用他们的缩写:

In [1]: import numpy as np

In [2]: import pandas as pd

In [3]: import xarray as xr

创建DataArray

我们可以通过以 numpy 数组或列表的形式提供数据,和可选的参数 dimensionscoordinates,来从头开始创建DataArray:

In [4]: data = xr.DataArray(np.random.randn(2, 3),
   ...:                     dims=('x', 'y'),
   ...:                     coords={'x': [10, 20]})
   ...: 

In [5]: data
Out[5]: 
<xarray.DataArray (x: 2, y: 3)>
array([[ 0.276, -1.087, -0.674],
       [ 0.114, -1.478,  0.525]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y

在此例中,我们创建了一个二维array,将dimensions分别命名为 xy,并赋予 x 维度 1020两个坐标标签。如果提供的是一个pandas的SeriesDataFrame,元数据将会被直接拷贝:

In [6]: xr.DataArray(pd.Series(range(3), index=list('abc'), name='foo'))
Out[6]: 
<xarray.DataArray 'foo' (dim_0: 3)>
array([0, 1, 2])
Coordinates:
  * dim_0    (dim_0) object 'a' 'b' 'c'

以下是DataArray的一些关键属性:

# 与 pandas 一样, values 是一个可以就地修改的 numpy array
In [7]: data.values
Out[7]: 
array([[ 0.276, -1.087, -0.674],
       [ 0.114, -1.478,  0.525]])

In [8]: data.dims
Out[8]: ('x', 'y')

In [9]: data.coords
Out[9]: 
Coordinates:
  * x        (x) int64 10 20

# 可以使用此字典存储任意元数据
In [10]: data.attrs
Out[10]: {}

更多 DataArray 内容,请参阅:xarray数据结构之DataArray

索引(Indexing)

xarray 支持4种索引方式。因为已经给 x 维度赋予了坐标标签,我们可以像 pandas 一样沿着该维度使用基于标签的方式索引。

# 通过整数标签定位的位置索引, 类似 numpy
In [11]: data[0, :]
Out[11]: 
<xarray.DataArray (y: 3)>
array([ 0.276, -1.087, -0.674])
Coordinates:
    x        int64 10
Dimensions without coordinates: y

# loc 或 "location": 通过坐标标签定位的位置索引, 类似 pandas
In [12]: data.loc[10]
Out[12]: 
<xarray.DataArray (y: 3)>
array([ 0.276, -1.087, -0.674])
Coordinates:
    x        int64 10
Dimensions without coordinates: y

# isel 或 "integer select":  通过维度名称和整数标签
In [13]: data.isel(x=0)
Out[13]: 
<xarray.DataArray (y: 3)>
array([ 0.276, -1.087, -0.674])
Coordinates:
    x        int64 10
Dimensions without coordinates: y

# sel 或 "select": 通过维度名称和坐标标签
In [14]: data.sel(x=10)
Out[14]: 
<xarray.DataArray (y: 3)>
array([ 0.276, -1.087, -0.674])
Coordinates:
    x        int64 10
Dimensions without coordinates: y

与位置索引不同的是,基于标签的索引方式可以使我们不知道 array 的组织结构的条件下进行索引。我们只需知道维度的名称和我们想要索引的标签。例如:(x=10) 可以进行索引,不需要知道 x 是数组的第一维还是第二维,也不需要知道 10 是 x 的第一个元素还是第二个元素。我们已经在创建数据时告诉xarray,x是第一个维度:xarray会跟踪该数据,而我们不必进行此操作。有关更多内容,请参阅: Indexing and selecting data

属性(Attributes)

当设置DataArray 时,通常会去设置元数据属性。一个有用选择是去设置 ['long_name']['units'],因为 xarray 在绘图时会自动使用他们来进行标记(如果有的话)。我们选择的这些特殊名称遵循 NetCDF Climate and Forecast (CF) Metadata Conventionsattrs 仅仅是一个Python字典,所以你可以赋予任何你希望的内容。

In [15]: data.attrs['long_name'] = 'random velocity'

In [16]: data.attrs['units'] = 'metres/sec'

In [17]: data.attrs['description'] = 'A random variable created as an example.'

In [18]: data.attrs['random_attribute'] = 123

In [19]: data.attrs
Out[19]: 
{'long_name': 'random velocity',
 'units': 'metres/sec',
 'description': 'A random variable created as an example.',
 'random_attribute': 123}

# 你也可以给坐标轴添加元数据
In [20]: data.x.attrs['units'] = 'x units'

计算(Computation)

Data arrays 的计算方式与 numpy ndarrays 非常相似:

In [21]: data + 10
Out[21]: 
<xarray.DataArray (x: 2, y: 3)>
array([[10.276,  8.913,  9.326],
       [10.114,  8.522, 10.525]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y

In [22]: np.sin(data)
Out[22]: 
<xarray.DataArray (x: 2, y: 3)>
array([[ 0.273, -0.885, -0.624],
       [ 0.113, -0.996,  0.501]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y

# 转置(transpose)
In [23]: data.T
Out[23]: 
<xarray.DataArray (y: 3, x: 2)>
array([[ 0.276,  0.114],
       [-1.087, -1.478],
       [-0.674,  0.525]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y
Attributes:
    long_name:         random velocity
    units:             metres/sec
    description:       A random variable created as an example.
    random_attribute:  123

In [24]: data.sum()
Out[24]: 
<xarray.DataArray ()>
array(-2.325)

但是,聚合操作可以使用维度名称代替轴号:

In [25]: data.mean(dim='x')
Out[25]: 
<xarray.DataArray (y: 3)>
array([ 0.195, -1.283, -0.074])
Dimensions without coordinates: y

算数运算根据维名称进行广播。 这意味着无需插入虚拟维度即可对齐:

In [26]: a = xr.DataArray(np.random.randn(3), [data.coords['y']])

In [27]: b = xr.DataArray(np.random.randn(4), dims='z')

In [28]: a
Out[28]: 
<xarray.DataArray (y: 3)>
array([ 0.405,  0.577, -1.715])
Coordinates:
  * y        (y) int64 0 1 2

In [29]: b
Out[29]: 
<xarray.DataArray (z: 4)>
array([-1.039, -0.371, -1.158, -1.344])
Dimensions without coordinates: z

In [30]: a + b
Out[30]: 
<xarray.DataArray (y: 3, z: 4)>
array([[-0.635,  0.034, -0.753, -0.94 ],
       [-0.462,  0.206, -0.581, -0.767],
       [-2.754, -2.086, -2.873, -3.059]])
Coordinates:
  * y        (y) int64 0 1 2
Dimensions without coordinates: z

这也意味着在大多数情况下,您无需担心维度顺序:

In [31]: data - data.T
Out[31]: 
<xarray.DataArray (x: 2, y: 3)>
array([[0., 0., 0.],
       [0., 0., 0.]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y

运算也根据索引标签对齐:

In [32]: data[:-1] - data[:1]
Out[32]: 
<xarray.DataArray (x: 1, y: 3)>
array([[0., 0., 0.]])
Coordinates:
  * x        (x) int64 10
Dimensions without coordinates: y

更多内容,请参阅:Computation

GroupBy

xarray 使用与 pandas 非常相似的 API ,进行分组操作(参阅: xarray教程之GroupBy: split-apply-combine)。

In [33]: labels = xr.DataArray(['E', 'F', 'E'], [data.coords['y']], name='labels')

In [34]: labels
Out[34]: 
<xarray.DataArray 'labels' (y: 3)>
array(['E', 'F', 'E'], dtype='<U1')
Coordinates:
  * y        (y) int64 0 1 2

In [35]: data.groupby(labels).mean('y')
Out[35]: 
<xarray.DataArray (x: 2, labels: 2)>
array([[-0.199, -1.087],
       [ 0.319, -1.478]])
Coordinates:
  * x        (x) int64 10 20
  * labels   (labels) object 'E' 'F'

In [36]: data.groupby(labels).map(lambda x: x - x.min())
Out[36]: 
<xarray.DataArray (x: 2, y: 3)>
array([[0.95 , 0.391, 0.   ],
       [0.787, 0.   , 1.199]])
Coordinates:
  * x        (x) int64 10 20
  * y        (y) int64 0 1 2
    labels   (y) <U1 'E' 'F' 'E'

绘图(Plotting)

可视化数据集是非常快速便捷的:

In [37]: data.plot()
Out[37]: <matplotlib.collections.QuadMesh at 0x7fc2c3a15d50>

在这里插入图片描述

注意自动产生的标签带有名称和单位。我们在添加元数据属性方面的努力取得了回报!这些图的许多方面都是可以自定义的:参阅 Plotting

pandas

Xarray对象可以通过使用 to_series(), to_dataframe()to_xarray()方法,轻松地与pandas对象之间进行转换:

In [38]: series = data.to_series()

In [39]: series
Out[39]: 
x   y
10  0    0.276232
    1   -1.087401
    2   -0.673690
20  0    0.113648
    1   -1.478427
    2    0.524988
dtype: float64

# convert back
In [40]: series.to_xarray()
Out[40]: 
<xarray.DataArray (x: 2, y: 3)>
array([[ 0.276, -1.087, -0.674],
       [ 0.114, -1.478,  0.525]])
Coordinates:
  * x        (x) int64 10 20
  * y        (y) int64 0 1 2

Datasets

是一个被赋予 DataArray 的类似字典(dict) 的容器。你可以认为它是一个具有多维结构的 :

In [41]: ds = xr.Dataset({'foo': data, 'bar': ('x', [1, 2]), 'baz': np.pi})

In [42]: ds
Out[42]: 
<xarray.Dataset>
Dimensions:  (x: 2, y: 3)
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y
Data variables:
    foo      (x, y) float64 0.2762 -1.087 -0.6737 0.1136 -1.478 0.525
    bar      (x) int64 1 2
    baz      float64 3.142

上面的操作将创建一个数据集,包含三个分别名为 foobarbazDataArray实例。 使用字典或点索引(相当于使用属性)将Dataset变量提取为DataArray对象,但请注意,赋值操作仅适用于字典索引:

In [43]: ds['foo']
Out[43]: 
<xarray.DataArray 'foo' (x: 2, y: 3)>
array([[ 0.276, -1.087, -0.674],
       [ 0.114, -1.478,  0.525]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y
Attributes:
    long_name:         random velocity
    units:             metres/sec
    description:       A random variable created as an example.
    random_attribute:  123

In [44]: ds.foo
Out[44]: 
<xarray.DataArray 'foo' (x: 2, y: 3)>
array([[ 0.276, -1.087, -0.674],
       [ 0.114, -1.478,  0.525]])
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y
Attributes:
    long_name:         random velocity
    units:             metres/sec
    description:       A random variable created as an example.
    random_attribute:  123

在创建 ds 时,我们指定 foo 与之前创建的data相同,bar 具有一个维度 x 及关联值“ 1”和“ 2”,而baz 是不与 ds 中任何维度关联的标量。 数据集中的变量可以具有不同的 dtype 甚至不同的维度,但是所有维度涉及的点都在相同共享的坐标系统内。即,如果两个变量的维度均为x,则该维度在两个变量中必须一致。

例如,在创建 ds xarray 时,它会自动将barDataArray foo对齐,即它们共享相同的坐标系,从而['x'] == ['x'] == ds['x'] 。 因此,以下操作在创建 ds['bar'] 时无需显式指定坐标 x :

In [45]: ds.bar.sel(x=10)
Out[45]: 
<xarray.DataArray 'bar' ()>
array(1)
Coordinates:
    x        int64 10

如果希望一次使用多个变量,则几乎可以将DataArray对象与Dataset对象(包括索引和算术)一起做。

更多 Dataset 内容,请参阅:xarray数据结构之Dataset

读写netCDF文件

NetCDF是xarray对象的推荐文件格式。地球科学的用户会发现,Dataset 数据模型看起来与netCDF文件非常相似(实际上是它的灵感来源)。

你可以通过使用 to_netcdf(), open_dataset()open_dataarray() 直接将 xarray 对象读写到磁盘:

In [46]: ds.to_netcdf('')

In [47]: xr.open_dataset('')
Out[47]: 
<xarray.Dataset>
Dimensions:  (x: 2, y: 3)
Coordinates:
  * x        (x) int64 10 20
Dimensions without coordinates: y
Data variables:
    foo      (x, y) float64 ...
    bar      (x) int64 ...
    baz      float64 ...

数据集通常分布在多个文件中(通常一个时间对应一个文件)。 xarray通过提供 open_mfdataset()save_mfdataset() 方法来支持此用例。更多有关内容,请参阅:Reading and writing files