xarray (之前的 xray) 是一个开源的python库。通过提供 pandas 的核心数据结构N维变形功能,从而将 pandas 的标签数据功能应用到物理科学领域。主要是想提供一个类似pandas并且能与pandas兼容的工具包来进行多维数组(而不是pandas 所擅长的表格数据)分析。采用的是地球科学领域广泛使用的自描述数据通用数据模型实现上述功能。
下面通过一些示例快速入门:
In [1]: import numpy as np
In [2]: import pandas as pd
In [3]: import xarray as xr
创建 DataArray
利用 numpy 数组或列表可以创建 DataArray ( coords 和 dims 为可选参数)
In [4]: xr.DataArray(np.random.randn(2, 3))
Out[4]:
<xarray.DataArray (dim_0: 2, dim_1: 3)>
array([[ 1.643563, -1.469388, 0.357021],
[-0.6746 , -1.776904, -0.968914]])
Dimensions without coordinates: dim_0, dim_1
In [5]: data = xr.DataArray(np.random.randn(2, 3), coords={'x': ['a', 'b']}, dims=('x', 'y'))
In [6]: data
Out[6]:
<xarray.DataArray (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
如果使用 Series 或 DataFrame 创建 DataArray,创建时将直接复制元数据信息:
In [7]: xr.DataArray(pd.Series(range(3), index=list('abc'), name='foo'))
Out[7]:
<xarray.DataArray 'foo' (dim_0: 3)>
array([0, 1, 2])
Coordinates:
* dim_0 (dim_0) object 'a' 'b' 'c'
下面是 DataArray 的一些属性:
# 类似 pandas 操作,可以直接赋值改变值
In [8]: data.values
Out[8]:
array([[-1.295, 0.414, 0.277],
[-0.472, -0.014, -0.363]])
In [9]: data.dims
Out[9]: ('x', 'y')
In [10]: data.coords
Out[10]:
Coordinates:
* x (x) <U1 'a' 'b'
# 可以使用字典存储元数据
In [11]: data.attrs
Out[11]: OrderedDict()
索引
xarray 借鉴了 pandas 的索引机制,因此在索引时非常快。xarray提供了四种索引方式:
# 通过整数进行索引
In [12]: data[[0, 1]]
Out[12]:
<xarray.DataArray (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
# 通过坐标标签索引
In [13]: data.loc['a':'b']
Out[13]:
<xarray.DataArray (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
# 通过维度名和整数标签索引
In [14]: data.isel(x=slice(2))
Out[14]:
<xarray.DataArray (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
# 利用维度名和坐标标签
In [15]: data.sel(x=['a', 'b'])
Out[15]:
<xarray.DataArray (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
计算
数组计算方式类似 numpy.ndarray
In [16]: data + 10
Out[16]:
<xarray.DataArray (x: 2, y: 3)>
array([[ 8.705476, 10.413738, 10.276662],
[ 9.527965, 9.98604 , 9.637457]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
In [17]: np.sin(data)
Out[17]:
<xarray.DataArray (x: 2, y: 3)>
array([[-0.962079, 0.402035, 0.273146],
[-0.454699, -0.013959, -0.354653]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
In [18]: data.T
Out[18]:
<xarray.DataArray (y: 3, x: 2)>
array([[-1.294524, -0.472035],
[ 0.413738, -0.01396 ],
[ 0.276662, -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
In [19]: data.sum()
Out[19]:
<xarray.DataArray ()>
array(-1.4526610277231344)
但在集合操作时使用维度名代替轴:
In [20]: data.mean(dim='x')
Out[20]:
<xarray.DataArray (y: 3)>
array([-0.883279, 0.199889, -0.042941])
Dimensions without coordinates: y
利用基于维度名的方式进行广播计算操作。这意味着不需要关心对齐操作:
In [21]: a = xr.DataArray(np.random.randn(3), [data.coords['y']])
In [22]: b = xr.DataArray(np.random.randn(4), dims='z')
In [23]: a
Out[23]:
<xarray.DataArray (y: 3)>
array([-0.006154, -0.923061, 0.895717])
Coordinates:
* y (y) int64 0 1 2
In [24]: b
Out[24]:
<xarray.DataArray (z: 4)>
array([ 0.805244, -1.206412, 2.565646, 1.431256])
Dimensions without coordinates: z
In [25]: a + b
Out[25]:
<xarray.DataArray (y: 3, z: 4)>
array([[ 0.79909 , -1.212565, 2.559492, 1.425102],
[-0.117817, -2.129472, 1.642585, 0.508195],
[ 1.700961, -0.310694, 3.461363, 2.326973]])
Coordinates:
* y (y) int64 0 1 2
Dimensions without coordinates: z
而且大多数情况下你都不要关心维度的顺序:
In [26]: data - data.T
Out[26]:
<xarray.DataArray (x: 2, y: 3)>
array([[ 0., 0., 0.],
[ 0., 0., 0.]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
以及基于索引标签的对齐操作:
In [27]: data[:-1] - data[:1]
Out[27]:
<xarray.DataArray (x: 1, y: 3)>
array([[ 0., 0., 0.]])
Coordinates:
* x (x) <U1 'a'
Dimensions without coordinates: y
使用类似 pandas 的 API 支持组操作
In [28]: labels = xr.DataArray(['E', 'F', 'E'], [data.coords['y']], name='labels')
In [29]: labels
Out[29]:
<xarray.DataArray 'labels' (y: 3)>
array(['E', 'F', 'E'],
dtype='<U1')
Coordinates:
* y (y) int64 0 1 2
In [30]: data.groupby(labels).mean('y')
Out[30]:
<xarray.DataArray (x: 2, labels: 2)>
array([[-0.508931, 0.413738],
[-0.417289, -0.01396 ]])
Coordinates:
* x (x) <U1 'a' 'b'
* labels (labels) object 'E' 'F'
In [31]: data.groupby(labels).apply(lambda x: x - x.min())
Out[31]:
<xarray.DataArray (x: 2, y: 3)>
array([[ 0. , 0.427698, 1.571185],
[ 0.822489, 0. , 0.931981]])
Coordinates:
* x (x) <U1 'a' 'b'
* y (y) int64 0 1 2
labels (y) <U1 'E' 'F' 'E'
pandas
xarray 对象 和 pandas 对象 可以非常方便的互相转换
In [32]: series = data.to_series()
In [33]: series
Out[33]:
x y
a 0 -1.294524
1 0.413738
2 0.276662
b 0 -0.472035
1 -0.013960
2 -0.362543
dtype: float64
# 反转换操作
In [34]: series.to_xarray()
Out[34]:
<xarray.DataArray (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) object 'a' 'b'
* y (y) int64 0 1 2
Dataset
xarray.Dataset 是 xarray.DataArray 对象的类字典容器,也可以认为这是一个多维的 DataFrame。
In [35]: ds = xr.Dataset({'foo': data, 'bar': ('x', [1, 2]), 'baz': np.pi})
In [36]: ds
Out[36]:
<xarray.Dataset>
Dimensions: (x: 2, y: 3)
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
Data variables:
baz float64 3.142
foo (x, y) float64 -1.295 0.4137 0.2767 -0.472 -0.01396 -0.3625
bar (x) int64 1 2
使用字典方法提取 DataSet 变量为 DataArray 对象:
In [37]: ds['foo']
Out[37]:
<xarray.DataArray 'foo' (x: 2, y: 3)>
array([[-1.294524, 0.413738, 0.276662],
[-0.472035, -0.01396 , -0.362543]])
Coordinates:
* x (x) <U1 'a' 'b'
Dimensions without coordinates: y
数据集中的变量可以有不同的类型甚至不同的维度。
Dataset 所使用的操作几乎全部适用于 DataArray 对象。
NetCDF
使用 to_netcdf,open_dataset 和 open_dataarray 方法可以直接读取及写 xarray 对象。
In [38]: ds.to_netcdf('example.nc')
In [39]: xr.open_dataset('example.nc')
Out[39]:
<xarray.Dataset>
Dimensions: (x: 2, y: 3)
Coordinates:
* x (x) object 'a' 'b'
Dimensions without coordinates: y
Data variables:
baz float64 3.142
foo (x, y) float64 -1.295 0.4137 0.2767 -0.472 -0.01396 -0.3625
bar (x) int64 1 2
后面会介绍一些更详细的内容。