前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >xarray | 索引及数据选择

xarray | 索引及数据选择

作者头像
bugsuse
发布2020-04-21 17:20:32
10.5K0
发布2020-04-21 17:20:32
举报

类似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'
  • 使用 sel 和 isel 方法
>> 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 相同的规则:

  • 使用整数或切片索引时,返回视图
  • 使用数组或列表索引时,返回副本

基于标签的索引更复杂:

  • 使用切片索引时,返回视图
  • 使用数组索引时,返回副本
  • 使用标量索引时,可能返回视图也可能是副本,取决于位置索引是整数还是切片。真正的规则依赖于pandas。

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')
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-10-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 气象杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档