类似pandas对象,xarray也对象支持沿着每个维度基于整数和标签的查找。 但是xarray对象还具有命名维度,因此您可以选择使用维度名称代替维度的整数索引。
xarray 支持四种索引方式 (见下表):
维度查找 | 索引查找 | DataArray | Dataset |
---|---|---|---|
Positional | By integer | arr[:, 0] | 不可用 |
Positional | By label | arr.loc[:, 'IA'] | 不可用 |
By name | By integer | arr.isel(space=0) or arr[dict(space=0)] | ds.isel(space=0) or ds[dict(space=0)] |
By name | By label | arr.sel(space='IA') or arr.loc[dict(space='IA')] | ds.sel(space='IA') or ds.loc[dict(space='IA')] |
基于位置的索引
直接对 DataArray 的索引类似 numpy 数组索引,只不过它返回的是一个新的 DataArray 对象。
>> arr = xr.DataArray(np.random.rand(4, 3),
[('time', pd.date_range('2000-01-01', periods=4)),
('space', ['IA', 'IL', 'IN'])])
>> arr
<xarray.DataArray (time: 4, space: 3)>
array([[ 0.792411, 0.977073, 0.417421],
[ 0.978191, 0.88482 , 0.115286],
[ 0.984572, 0.576699, 0.206171],
[ 0.84849 , 0.539935, 0.279976]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'
# 如果仅提供一个位置索引,默认对所有列的行索引
>> arr[::2]
<xarray.DataArray (time: 2, space: 3)>
array([[ 0.792411, 0.977073, 0.417421],
[ 0.984572, 0.576699, 0.206171]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-03
* space (space) <U2 'IA' 'IL' 'IN'
# 对所有行的列索引
>> arr[:, ::2]
<xarray.DataArray (time: 4, space: 2)>
array([[ 0.792411, 0.417421],
[ 0.978191, 0.115286],
[ 0.984572, 0.206171],
[ 0.84849 , 0.279976]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IN'
# 选择单个数
>> arr[0, 0]
<xarray.DataArray ()>
array(0.7924108938509337)
Coordinates:
time datetime64[ns] 2000-01-01
space <U2 'IA'
# 按列表中的顺序选择行列
>> arr[[0, 3, 1, 2], [2, 0, 1]]
<xarray.DataArray (time: 4, space: 3)>
array([[ 0.417421, 0.792411, 0.977073],
[ 0.279976, 0.84849 , 0.539935],
[ 0.115286, 0.978191, 0.88482 ],
[ 0.206171, 0.984572, 0.576699]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-04 2000-01-02 2000-01-03
* space (space) <U2 'IN' 'IA' 'IL'
xarray 也提供了和 pandas 类似的标签索引的方法 (使用的 pandas.Index 钩子),使用 .loc 属性:
>> arr.loc['2000-01-01':'2000-01-02', 'IN']
<xarray.DataArray (time: 2)>
array([ 0.417421, 0.115286])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
space <U2 'IN'
pandas 中提供的基于标签的索引方式可以应用到 xarray 中 (比如:单标签,标签切片,标签数组,逻辑数组)。
除了利用标签索引提取数据之外,也可以进行赋值操作:
>> arr.loc['2000-01-01', ['IL', 'IN']] = np.random.rand(2)
>> arr
<xarray.DataArray (time: 4, space: 3)>
array([[ 0.792411, 0.520405, 0.068328],
[ 0.978191, 0.88482 , 0.115286],
[ 0.984572, 0.576699, 0.206171],
[ 0.84849 , 0.539935, 0.279976]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'
标签维度索引
使用标签维度索引时不需要依赖于维度顺序。主要有两种方式:
# 根据位置索引
>> arr[dict(space=slice(0, 3, 2), time=slice(None, 2))]
<xarray.DataArray (time: 2, space: 2)>
array([[ 0.792411, 0.068328],
[ 0.978191, 0.115286]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IN'
# 利用维度坐标标签索引
>> arr.loc[dict(time=slice('2000-01-01', '2000-01-02'))]
<xarray.DataArray (time: 2, space: 3)>
array([[ 0.792411, 0.520405, 0.068328],
[ 0.978191, 0.88482 , 0.115286]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL' 'IN'
>> arr.isel(space = slice(0, 3, 2), time = slice(None, 2))
<xarray.DataArray (time: 2, space: 2)>
array([[ 0.792411, 0.068328],
[ 0.978191, 0.115286]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IN'
>> arr.sel(time = slice('2000-01-01', '2000-01-02'))
<xarray.DataArray (time: 2, space: 3)>
array([[ 0.792411, 0.520405, 0.068328],
[ 0.978191, 0.88482 , 0.115286]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL' 'IN'
这些方法的参数可以是 单个标签值, slice 对象 或 1D数组。
注意:
不要使用 isel* 和 sel* 进行赋值操作,因为一旦赋值失败是没有提示的:
# 不要这样做
>> arr.isel(space=0) = 0
应该使用常规的赋值方式:
# 应该这样
>> arr[dict(space=0)] = 0
点索引
xarray 点索引支持使用类列表对象进行多标签维度索引。isel_points 方法提供了类似 numpy 多列表索引数据 (比如:arr[[0, 1], [0, 1]]
) 的方式:
>> da = xr.DataArray(np.arange(36).reshape((6, 6)), dims=['x', 'y'])
>> da
<xarray.DataArray (x: 6, y: 6)>
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]])
Dimensions without coordinates: x, y
>> da.isel_points(x=[0, 1, 2, 3, 4, 5], y=[0, 1, 2, 3, 4, 5])
<xarray.DataArray (points: 6)>
array([ 0, 7, 14, 21, 28, 35])
Dimensions without coordinates: points
sel_points 方可可以通过标签进行点索引 (与 pandas 中的 lookup 方法相同):
>> times = pd.to_datetime(['2000-01-03', '2000-01-02', '2000-01-01'])
>> arr.sel_points(space=['IA', 'IL', 'IN'], time=times)
<xarray.DataArray (points: 3)>
array([ 0.984572, 0.88482 , 0.068328])
Coordinates:
time (points) datetime64[ns] 2000-01-03 2000-01-02 2000-01-01
space (points) <U2 'IA' 'IL' 'IN'
Dimensions without coordinates: points
Dataset 索引
上述方法同样可以应用于 Dataset 对象,然后返回一个新的 Dataset 对象:
>> ds = arr.to_dataset(name = 'ds')
>> ds
<xarray.Dataset>
Dimensions: (space: 3, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
ds (time, space) float64 0.7924 0.5204 0.06833 0.9782 0.8848 ...
# 查看 ds 变量数据
>> ds.ds.data
array([[ 0.79241089, 0.52040491, 0.06832842],
[ 0.97819127, 0.88482015, 0.11528646],
[ 0.98457165, 0.57669922, 0.20617116],
[ 0.84849003, 0.53993486, 0.27997644]])
# 获取第一个时间对应的数据
>> ds.isel(time = 0)
<xarray.Dataset>
Dimensions: (space: 3)
Coordinates:
time datetime64[ns] 2000-01-01
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
ds (space) float64 0.7924 0.5204 0.06833
# 获取指定 space 和 time 的数据
>> ds.isel(space = [0, 2], time = [0, 3])
<xarray.Dataset>
Dimensions: (space: 2, time: 2)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-04
* space (space) <U2 'IA' 'IN'
Data variables:
ds (time, space) float64 0.7924 0.06833 0.8485 0.28
>> ds.isel(space = [0, 2], time = [0, 3]).ds.data
array([[ 0.79241089, 0.06832842],
[ 0.84849003, 0.27997644]])
# 指定时间
>> ds.sel(time='2000-01-01')
<xarray.Dataset>
Dimensions: (space: 3)
Coordinates:
time datetime64[ns] 2000-01-01
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
ds (space) float64 0.7924 0.5204 0.06833
目前不支持使用索引对子数据集进行赋值 (如: ds[dict(space=0)] = 1
)。
丢弃标签
drop (适用于 Dataset 和 DataArray) 方法会返回具有沿着某一维度丢弃的索引标签的新对象,不改变原对象:
>> ds.drop(['IN', 'IL'], dim='space')
<xarray.Dataset>
Dimensions: (space: 1, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA'
Data variables:
ds (time, space) float64 0.7924 0.9782 0.9846 0.8485
最邻近查找
基于标签查找的方法 (sel,reindex,reindex_like) 均支持 method 和 tolerance 关键词参数 。方法参数可以使用 'pad','backfill','nearest' 执行最邻近查找:
>> ds.sel(space = [0.9, 1.8], method='nearest')
<xarray.Dataset>
Dimensions: (space: 2, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) int32 1 2
Data variables:
ds (time, space) float64 0.7924 0.5204 0.9782 0.8848 0.9846 0.5767 ...
>> ds.sel(space = [0.5, 1.6], method= 'backfill')
<xarray.Dataset>
Dimensions: (space: 2, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) int32 1 2
Data variables:
ds (time, space) float64 0.7924 0.5204 0.9782 0.8848 0.9846 0.5767 ...
>> ds.reindex(space = [0.9, 1.8, 2.5, 3.1], method='pad')
<xarray.Dataset>
Dimensions: (space: 4, time: 4)
Coordinates:
* space (space) float64 0.9 1.8 2.5 3.1
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
Data variables:
ds (time, space) float64 nan 0.7924 0.5204 0.06833 nan 0.9782 ...
以上方法均是针对维度坐标变量。
tolerance 是限制匹配时的最大查找距离 ( reindex 方法):
>> ds.reindex(space = [0.9, 1.8, 2.5, 3.1], method='pad', tolerance=1.5)
<xarray.Dataset>
Dimensions: (space: 4, time: 4)
Coordinates:
* space (space) float64 0.9 1.8 2.5 3.1
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
Data variables:
ds (time, space) float64 nan 0.7924 0.5204 0.06833 nan 0.9782 ...
如果 .sel 参数是 slice 对象的话,则不支持方法参数。会返回 NotImplementedError
where 掩膜
上述索引方法通常会返回原对象的子集,而有时候需要返回和原对象大小相同的新对象,但有些元素被掩盖住。使用 where 方法可以实现上述操作:
>> arr = xr.DataArray(np.arange(16).reshape(4, 4), dims=['x', 'y'])
>> arr.where(np.logical_and(arr.x > 0, arr.y < 3))
<xarray.DataArray (x: 4, y: 4)>
array([[ nan, nan, nan, nan],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ nan, nan, nan, nan]])
Dimensions without coordinates: x, y
在索引多维数组时非常有用。比如 对图像进行2D掩膜。where 遵循的是所有常规 xarray 广播和对齐原则,索引对象和条件之间二元操作
>> arr.where(arr2.y < 2)
<xarray.DataArray (x: 4, y: 4)>
array([[ 0., 1., nan, nan],
[ 4., 5., nan, nan],
[ 8., 9., nan, nan],
[ 12., 13., nan, nan]])
Dimensions without coordinates: x, y
默认情况下, where 方法返回和原数组相同大小的新对象。有时候会需要将掩膜部分剪切掉,可以使用 drop = True参数实现:
>> arr.where(arr.y < 2, drop=True)
<xarray.DataArray (x: 4, y: 2)>
array([[ 0., 1.],
[ 4., 5.],
[ 8., 9.],
[ 12., 13.]])
Dimensions without coordinates: x, y
多层索引
和 pandas 一样,使用 sel 和 loc 方法可以进行多层索引。也可以使用多索引器(比如:元组切片,标签,标签列表,其它pandas允许的选择器)进行多索引切片:
>> midx = pd.MultiIndex.from_product([list('abc'), [0, 1]],
names=('one', 'two'))
>> mda = xr.DataArray(np.random.rand(6, 3), [('x', midx), ('y', range(3))])
>> mda
<xarray.DataArray (x: 6, y: 3)>
array([[ 0.412587, 0.188182, 0.861166],
[ 0.592771, 0.624895, 0.057569],
[ 0.317333, 0.968225, 0.225619],
[ 0.229326, 0.345359, 0.087062],
[ 0.721171, 0.485591, 0.065315],
[ 0.022853, 0.057333, 0.99728 ]])
Coordinates:
* x (x) MultiIndex
- one (x) object 'a' 'a' 'b' 'b' 'c' 'c'
- two (x) int64 0 1 0 1 0 1
* y (y) int32 0 1 2
>> mda.sel(x = (list('bc'), [0,3]))
<xarray.DataArray (x: 2, y: 3)>
array([[ 0.317333, 0.968225, 0.225619],
[ 0.721171, 0.485591, 0.065315]])
Coordinates:
* x (x) MultiIndex
- one (x) object 'b' 'c'
- two (x) int64 0 0
* y (y) int32 0 1 2
通过标签列表,元组或元组切片选择多个元素:
>> mda.sel(x=[('a', 0), ('b', 1)])
当然也可以使用字典的方式索引数据:
>> mda.sel(x={'one': 'a', 'two': 0})
<xarray.DataArray (y: 3)>
array([ 0.412587, 0.188182, 0.861166])
Coordinates:
x object ('a', 0)
* y (y) int32 0 1 2
为了方便操作,sel 方法使用多索引层作为关键词参数进行索引:
>> mda.sel(x={'one': 'a', 'two': 0})
<xarray.DataArray (y: 3)>
array([ 0.412587, 0.188182, 0.861166])
Coordinates:
x object ('a', 0)
* y (y) int32 0 1 2
注意:
使用 sel 方法不能混合维度索引和层索引,否则会导致异常。比如:
mda.sel(x={'one': 'a'}, two=0)
类似 pandas,xarray 可以从多索引中选择部分索引。当多索引将为单索引时,返回的对象会重命名维度和坐标。
>> mda.loc[{'one': 'a'}, ...]
<xarray.DataArray (two: 2, y: 3)>
array([[ 0.412587, 0.188182, 0.861166],
[ 0.592771, 0.624895, 0.057569]])
Coordinates:
* two (two) int64 0 1
* y (y) int32 0 1 2
多维索引
xarray 目前不支持多维度索引,但在未来可能会支持。
复制和视图
数组索引返回视图还是副本依赖于标签。对于整数索引来说,使用numpy 相同的规则:
基于标签的索引更复杂:
xarray 返回的结果比 pandas 更明确,不会返回 SettingWithCopy warnings
对齐与重索引
xarray 中的 reindex,reindex_like 及 align 会将 Dataset 或 DataArray 添加到响应维度的新坐标集。原始数据是新对象的子集,而原数据中没有的数据用 Nan填充。
xarray 在执行合并多对象操作时会自动对齐。手动对齐能够提高效率。
使用 reindex 方法可以索引特定维度:
>> arr.reindex(space=['IA', 'CA'])
<xarray.DataArray (time: 4, space: 2)>
array([[ 0.12697 , nan],
[ 0.897237, nan],
[ 0.451376, nan],
[ 0.543026, nan]])
Coordinates:
* space (space) <U2 'IA' 'CA'
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
reindex_like 方法是非常有用的快捷方式。
>> foo = arr.rename('foo')
>> baz = (10 * arr[:2, :2]).rename('baz')
>> baz
<xarray.DataArray 'baz' (x: 2, y: 2)>
array([[ 0, 10],
[40, 50]])
Dimensions without coordinates: x, y
用 baz 对 foo 进行重索引时,按照 baz 索引沿着每一个维度选择前两个值:
>> foo.reindex_like(baz)
使用 foo 对 baz 进行重索引时,会按照 foo 索引扩大 baz (用 NaN填充) :
>> baz.reindex_like(foo)
align 函数可以更方便的执行类数据库操作 ('inner'
, 'outer'
, 'left',
'right'
)
方法与 pandas 操作类似。
>> xr.align(foo, baz, join='inner')
>> xr.align(foo, baz, join='outer')
reindex_like 和 align 方法可以在 Dataset 和 DataArray 对象间交互使用。
In [56]: ds
Out[56]:
<xarray.Dataset>
Dimensions: (space: 3, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
foo (time, space) float64 0.127 -10.0 -10.0 0.8972 0.3767 0.3362 ...
In [57]: ds.reindex_like(baz)
Out[57]:
<xarray.Dataset>
Dimensions: (space: 2, time: 2)
Coordinates:
* space (space) object 'IA' 'IL'
* time (time) datetime64[ns] 2000-01-01 2000-01-02
Data variables:
foo (time, space) float64 0.127 -10.0 0.8972 0.3767
In [58]: other = xr.DataArray(['a', 'b', 'c'], dims='other')
# this is a no-op, because there are no shared dimension names
In [59]: ds.reindex_like(other)
Out[59]:
<xarray.Dataset>
Dimensions: (space: 3, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
foo (time, space) float64 0.127 -10.0 -10.0 0.8972 0.3767 0.3362 ...
缺省坐标标签
每个维度的标签坐标是可选的。没有坐标标签时,基于标签的索引方法 sel 和 loc 使用标准的基于整数和位置的索引。
>> array = xr.DataArray([1, 2, 3], dims='x')
>> array
<xarray.DataArray (x: 3)>
array([1, 2, 3])
Dimensions without coordinates: x
>> array.sel(x = [0])
<xarray.DataArray (x: 1)>
array([1])
Dimensions without coordinates: x
如果两个 xarray 对象至少有一个没有坐标标签,只要有相同的维度名和大小,同样可以执行对齐操作。否则,会导致异常:
>> xr.align(array, array[:2])
ValueError: arguments without labels along dimension 'x' cannot be aligned because they have different dimension sizes: {2, 3}
基索引(Underlying Indexs)
xarray 使用 pandas.Index 执行索引操作。使用 indexes 属性可以获取基索引。
>> ds
<xarray.Dataset>
Dimensions: (space: 3, time: 4)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) int32 1 2 3
Data variables:
ds (time, space) float64 0.7924 0.5204 0.06833 0.9782 0.8848 ...
>> ds.indexes
time: DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[ns]', name='time', freq='D')
space: Int64Index([1, 2, 3], dtype='int64', name='space')
>> ds.indexes['time']
DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[ns]', name='time', freq='D')
使用 get_index 可以获取维度索引。如果没有坐标标签,默认返回 panda.RangeIndex
>> ds.get_index('time')
DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[ns]', name='time', freq='D')