xarray指南:索引和选择数据 - 位置和名称索引

目录

本文翻译自 xarray 官方文档 Indexing and selecting data 的部分内容。

首先导入需要的库。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import xarray as xr

xr.set_options(display_style="text")

为了在实战中学习,使用 nwpc-oper/nwpc-data 库加载一个示例数据。

from nwpc_data.grib.cfgrib import load_field_from_file
from nwpc_data.data_finder import find_local_file

加载 850hPa 温度场

t850 = load_field_from_file(
    file_path=find_local_file(
        "grapes_gfs_gmf/grib2/orig",
        start_time="2020031800",
        forecast_time="105h"
    ),
    parameter="t",
    level_type="isobaricInhPa",
    level=850,
)
t850
<xarray.DataArray 't' (latitude: 720, longitude: 1440)>
[1036800 values with dtype=float32]
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
  * latitude       (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
  * longitude      (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    GRIB_units:                               K
    GRIB_name:                                Temperature
    GRIB_cfName:                              air_temperature
    GRIB_cfVarName:                           t
    GRIB_dataType:                            fc
    GRIB_missingValue:                        9999
    GRIB_numberOfPoints:                      1036800
    GRIB_typeOfLevel:                         isobaricInhPa
    GRIB_NV:                                  0
    GRIB_stepUnits:                           1
    GRIB_stepType:                            instant
    GRIB_gridType:                            regular_ll
    GRIB_gridDefinitionDescription:           Latitude/longitude 
    GRIB_Nx:                                  1440
    GRIB_iDirectionIncrementInDegrees:        0.25
    GRIB_iScansNegatively:                    0
    GRIB_longitudeOfFirstGridPointInDegrees:  0.0
    GRIB_longitudeOfLastGridPointInDegrees:   359.75
    GRIB_Ny:                                  720
    GRIB_jDirectionIncrementInDegrees:        0.25
    GRIB_jPointsAreConsecutive:               0
    GRIB_jScansPositively:                    0
    GRIB_latitudeOfFirstGridPointInDegrees:   89.875
    GRIB_latitudeOfLastGridPointInDegrees:    -89.875
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature

xarray 提供了非常灵活的索引功能,结合 NumPy 和 pandas 的优秀特性来进行数据选择。

访问 DataArray 对象的元素的最基本方法是使用 Python 的 [] 语法,例如 array[i, j],其中 ij 都是整数。 由于 xarray 对象可以存储与数组的每个维度相对应的坐标,因此也可以使用类似于 pandas.DataFrame.loc 的基于标签的索引。 在基于标签的索引中,将自动从坐标值中查找元素位置 i

xarray 对象的维度有名称,因此您也可以按名称查找维度,而不用记住它们的位置顺序。

因此,xarray 总共支持四种不同类型的索引,如下所述并在此表中进行了总结:

维度查找索引查找DataArray 语法Dataset 语法
位置整数da[:, 0]不可用
位置标签da.loc[:, "IA"]不可用
名称整数da.isel(space=0)da[dict(space=0)]ds.isel(space=0)ds[dict(space=0)]
名称标签da.sel(space="IA")da.loc[dict(space="IA")ds.sel(space="IA")ds.loc[dict(sapce="IA")]

通过提供 DataArray 对象作为索引器,所有方法也可以使用更高级的索引。有关详细信息,请参见向量化索引。

位置索引

直接使用 DataArray 索引(大多数情况下)就像对 numpy 数组索引一样,只是返回的对象始终是另一个 DataArray

da = xr.DataArray(
    np.random.rand(4, 3),
    [
        ('time', pd.date_range('2000-01-01', periods=4)),
        ('space', ['IA', 'IL', 'IN']),
    ],
)
da
<xarray.DataArray (time: 4, space: 3)>
array([[0.75021404, 0.02706204, 0.01871538],
       [0.25646947, 0.23231313, 0.6944673 ],
       [0.62417497, 0.55133703, 0.50926407],
       [0.98872876, 0.11967967, 0.44832905]])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
  * space    (space) <U2 'IA' 'IL' 'IN'
da[:2]
<xarray.DataArray (time: 2, space: 3)>
array([[0.75021404, 0.02706204, 0.01871538],
       [0.25646947, 0.23231313, 0.6944673 ]])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
  * space    (space) <U2 'IA' 'IL' 'IN'
da[0, 0]
da[:, [2, 1]]
<xarray.DataArray (time: 4, space: 2)>
array([[0.01871538, 0.02706204],
       [0.6944673 , 0.23231313],
       [0.50926407, 0.55133703],
       [0.44832905, 0.11967967]])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
  * space    (space) <U2 'IN' 'IL'

属性在所有索引操作中都会保留。

注意:如向量化索引中所述,当使用多个数组(例如 da[[0,1],[0,1]] 进行索引时,位置索引与 NumPy 不一致。

实战

t850[:360]
<xarray.DataArray 't' (latitude: 360, longitude: 1440)>
[518400 values with dtype=float32]
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
  * latitude       (latitude) float64 89.88 89.62 89.38 ... 0.625 0.375 0.125
  * longitude      (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature
t850[80, 80]
<xarray.DataArray 't' ()>
array(263.99234, dtype=float32)
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
    latitude       float64 69.88
    longitude      float64 20.0
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature
t850[:, np.arange(1439, -1, -1)]
<xarray.DataArray 't' (latitude: 720, longitude: 1440)>
[1036800 values with dtype=float32]
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
  * latitude       (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
  * longitude      (longitude) float64 359.8 359.5 359.2 359.0 ... 0.5 0.25 0.0
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature

就像 pandas 一样,xarray 还支持基于标签的索引。 因为我们在后台使用了 pandas.Index,所以基于标签的索引非常快。 要进行基于标签的索引,请使用 loc 属性:

da.loc["2000-01-01":"2000-01-02", "IA"]
<xarray.DataArray (time: 2)>
array([0.75021404, 0.25646947])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
    space    <U2 'IA'

在此示例中,所选对象是数组的子集,沿着第一个坐标 time 在范围 2000-01-01:2000-01-02 中,第二个坐标 space 中的值为 IA

您可以执行 pandas 支持的任何标签索引操作,包括使用单个标签,切片和数组进行索引,以及使用布尔数组进行索引。 像 pandas 一样,xarray 中基于标签的索引包括开始和结束范围。

还支持使用基于标签的索引设置值:

da.loc['2000-01-01', ['IL', 'IN']] = -10
da
<xarray.DataArray (time: 4, space: 3)>
array([[  0.75021404, -10.        , -10.        ],
       [  0.25646947,   0.23231313,   0.6944673 ],
       [  0.62417497,   0.55133703,   0.50926407],
       [  0.98872876,   0.11967967,   0.44832905]])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
  * space    (space) <U2 'IA' 'IL' 'IN'

实战

t850.loc[80.625:43.375, 25]
<xarray.DataArray 't' (latitude: 150)>
array([265.90234, 266.12234, 266.89233, 266.99234, 267.10236, 267.26233,
       ...skip...
       273.47235, 274.89233, 275.42233, 275.50235, 275.64233, 275.98233],
      dtype=float32)
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
  * latitude       (latitude) float64 80.62 80.38 80.12 ... 43.88 43.62 43.38
    longitude      float64 25.0
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature

使用维度名称索引

使用维度名称,我们不必依赖维度顺序,可以显式使用它们来切片数据。 有两种方法可以做到这一点:

  1. 使用字典作为数组位置或基于标签的数组索引的参数:
# 使用整形数组索引
da[dict(space=0, time=slice(None, 2))]
<xarray.DataArray (time: 2)>
array([0.75021404, 0.25646947])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
    space    <U2 'IA'
# 使用维度坐标标签索引
da.loc[dict(time=slice("2000-01-01", "2000-01-02"))]
<xarray.DataArray (time: 2, space: 3)>
array([[  0.75021404, -10.        , -10.        ],
       [  0.25646947,   0.23231313,   0.6944673 ]])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
  * space    (space) <U2 'IA' 'IL' 'IN'
  1. 使用 sel()isel() 方法:
# 使用整型数组索引
da.isel(space=0, time=slice(None, 2))
<xarray.DataArray (time: 2)>
array([0.75021404, 0.25646947])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
    space    <U2 'IA'
# 使用维度坐标标签索引
da.sel(time=slice("2000-01-01", "2000-01-02"))
<xarray.DataArray (time: 2, space: 3)>
array([[  0.75021404, -10.        , -10.        ],
       [  0.25646947,   0.23231313,   0.6944673 ]])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02
  * space    (space) <U2 'IA' 'IL' 'IN'

这些方法的参数可以是可以沿关键字给定的维索引数组的任何对象,例如,单个值的标签,Python slice 对象或一维数组。

注意

我们希望能够使用方括号内的标注为名称进行索引,但是不幸的是,Python 尚不支持使用诸如 da[space=0] 之类的关键字参数进行索引。

实战

t850[dict(latitude=50, longitude=slice(None, 2))]
<xarray.DataArray 't' (longitude: 2)>
array([258.90234, 258.96234], dtype=float32)
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
    latitude       float64 77.38
  * longitude      (longitude) float64 0.0 0.25
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature
t850.loc[dict(longitude=slice(50.25, 60.25))]
<xarray.DataArray 't' (latitude: 720, longitude: 41)>
array([[249.11235, 249.10234, 249.05234, ..., 249.08234, 249.06235, 249.06235],
       [249.24234, 249.23235, 249.26234, ..., 249.20235, 249.18234, 249.18234],
       [249.34235, 249.34235, 249.31235, ..., 249.24234, 249.24234, 249.22235],
       ...,
       [237.09235, 237.51234, 237.49234, ..., 237.97235, 237.87234, 237.81235],
       [236.79234, 237.15234, 236.82234, ..., 237.24234, 237.00235, 237.26234],
       [236.51234, 236.41234, 236.53235, ..., 236.43234, 236.66234, 236.56235]],
      dtype=float32)
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
  * latitude       (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
  * longitude      (longitude) float64 50.25 50.5 50.75 ... 59.75 60.0 60.25
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature
t850.isel(latitude=50, longitude=slice(None, 2))
<xarray.DataArray 't' (longitude: 2)>
array([258.90234, 258.96234], dtype=float32)
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
    latitude       float64 77.38
  * longitude      (longitude) float64 0.0 0.25
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature
t850.sel(longitude=slice(50.25, 60.25))
<xarray.DataArray 't' (latitude: 720, longitude: 41)>
array([[249.11235, 249.10234, 249.05234, ..., 249.08234, 249.06235, 249.06235],
       [249.24234, 249.23235, 249.26234, ..., 249.20235, 249.18234, 249.18234],
       [249.34235, 249.34235, 249.31235, ..., 249.24234, 249.24234, 249.22235],
       ...,
       [237.09235, 237.51234, 237.49234, ..., 237.97235, 237.87234, 237.81235],
       [236.79234, 237.15234, 236.82234, ..., 237.24234, 237.00235, 237.26234],
       [236.51234, 236.41234, 236.53235, ..., 236.43234, 236.66234, 236.56235]],
      dtype=float32)
Coordinates:
    time           datetime64[ns] ...
    step           timedelta64[ns] ...
    isobaricInhPa  int64 ...
  * latitude       (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
  * longitude      (longitude) float64 50.25 50.5 50.75 ... 59.75 60.0 60.25
    valid_time     datetime64[ns] ...
Attributes:
    GRIB_paramId:                             130
    GRIB_shortName:                           t
    ...skip...
    long_name:                                Temperature
    units:                                    K
    standard_name:                            air_temperature

参考

http://xarray.pydata.org/en/stable/indexing.html