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]
,其中 i
和 j
都是整数。
由于 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
使用维度名称索引
使用维度名称,我们不必依赖维度顺序,可以显式使用它们来切片数据。 有两种方法可以做到这一点:
- 使用字典作为数组位置或基于标签的数组索引的参数:
# 使用整形数组索引
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'
- 使用
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