类似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')
本文分享自微信公众号 - 气象杂货铺(meteogs),作者:lightning
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2017-10-07
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句