Indexing and selecting data
Xarray提供了极其灵活的索引例程,结合了NumPy和pandas在数据选择方面的最佳特性。
访问DataArray对象元素的最基本方法是使用Python的[]语法,比如array[i,j]
,其中I和j都是整数。由于xarray对象可以存储与数组的每个维度相对应的坐标,所以基于标签的索引类似于pandas。DataFrame.loc也是可以的。在基于标签的索引中,从坐标值中自动查找元素位置I。
xarray对象的维度有名称,因此您也可以通过名称查找维度,而不是记住它们的位置顺序。
Quick overview
Positional indexing
直接索引DataArray的工作方式(大部分)与索引numpy数组一样,只是返回的对象总是另一个DataArray:
import xarray as xr
import numpy as np
import pandas as pd
da = xr.DataArray(
np.random.rand(4, 3),
[
("time", pd.date_range("2000-01-01", periods=4)),
("space", ["IA", "IL", "IN"]),
],
)
print(da[:2])
"""<xarray.DataArray (time: 2, space: 3)>
array([[0.21404789, 0.916436 , 0.9182366 ],
[0.11161617, 0.72361921, 0.28669233]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL' 'IN'
"""
print(da[0, 0])
"""<xarray.DataArray ()>
array(0.21404789)
Coordinates:
time datetime64[ns] 2000-01-01
space <U2 'IA'
"""
print(da[:, [2, 1]])
"""
<xarray.DataArray (time: 4, space: 2)>
array([[0.9182366 , 0.916436 ],
[0.28669233, 0.72361921],
[0.05506156, 0.36749797],
[0.92949472, 0.20359987]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IN' 'IL'
"""
Xarray也支持基于标签的索引,就像pandas一样。因为我们用pandas.Index下的索引,基于标签的索引非常快。要进行基于标签的索引,请使用loc属性:
da.loc["2000-01-01":"2000-01-02", "IA"]
"""Out[5]:
<xarray.DataArray (time: 2)>
array([0.127, 0.897])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
space <U2 'IA'"""
Indexing with dimension names
有了维度名称,我们就不必依赖维度顺序,可以显式地使用它们来切片数据。有两种方法可以做到这一点
- 使用sel()和isel()方便的方法:
# index by integer array indices
da.isel(space=0, time=slice(None, 2))
"""Out[8]:
<xarray.DataArray (time: 2)>
array([0.127, 0.897])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
space <U2 'IA'"""
# index by dimension coordinate labels
da.sel(time=slice("2000-01-01", "2000-01-02"))
"""Out[9]:
<xarray.DataArray (time: 2, space: 3)>
array([[ 0.127, -10. , -10. ],
[ 0.897, 0.377, 0.336]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL' 'IN'"""
- 使用字典作为基于数组位置或标签的数组索引的参数
# index by integer array indices
da[dict(space=0, time=slice(None, 2))]
"""Out[10]:
<xarray.DataArray (time: 2)>
array([0.127, 0.897])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
space <U2 'IA'"""
# index by dimension coordinate labels
da.loc[dict(time=slice("2000-01-01", "2000-01-02"))]
"""Out[11]:
<xarray.DataArray (time: 2, space: 3)>
array([[ 0.127, -10. , -10. ],
[ 0.897, 0.377, 0.336]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL' 'IN'"""
Nearest neighbor lookups
基于标签的选择方法sel()、reindex()和reindex_like()
都支持方法和容差关键字参数。方法参数允许通过使用“填充”、“回填”或“最近的”方法来启用最近邻(不精确)查找:
da = xr.DataArray([1, 2, 3], [("x", [0, 1, 2])])
da.sel(x=[1.1, 1.9], method="nearest")
"""Out[13]:
<xarray.DataArray (x: 2)>
array([2, 3])
Coordinates:
* x (x) int64 1 2"""
da.sel(x=0.1, method="backfill")
"""Out[14]:
<xarray.DataArray ()>
array(2)
Coordinates:
x int64 1"""
da.reindex(x=[0.5, 1, 1.5, 2, 2.5], method="pad")
"""Out[15]:
<xarray.DataArray (x: 5)>
array([1, 2, 2, 3, 3])
Coordinates:
* x (x) float64 0.5 1.0 1.5 2.0 2.5"""
method : {None, “nearest”, “pad”, “ffill”, “backfill”, “bfill”}, optional
Method to use for inexact matches:
- None (default): only exact matches
- pad / ffill: propagate last valid index value forward
- backfill / bfill: propagate next valid index value backward
- nearest: use nearest valid index value
公差限制了不精确查找的有效匹配的最大距离:
da.reindex(x=[1.1, 1.5], method="nearest", tolerance=0.2)
"""Out[16]:
<xarray.DataArray (x: 2)>
array([ 2., nan])
Coordinates:
* x (x) float64 1.1 1.5"""
如果参数是一个切片对象,暂时还不支持
da.sel(x=slice(1, 3), method="nearest")
NotImplementedError
然而,你不需要使用方法来做不精确的切片。只要索引标签是单调递增的,切片就已经返回该范围内的所有值(包括):
da.sel(x=slice(0.9, 3.1))
"""Out[18]:
<xarray.DataArray (x: 2)>
array([2, 3])
Coordinates:
* x (x) int64 1 2"""
Dataset indexing
我们还可以使用这些方法同时索引数据集中的所有变量,返回一个新的数据集:
da = xr.DataArray(
np.random.rand(4, 3),
[
("time", pd.date_range("2000-01-01", periods=4)),
("space", ["IA", "IL", "IN"]),
],
)
ds = da.to_dataset(name="foo")
ds.isel(space=[0], time=[0])
"""Out[23]:
<xarray.Dataset>
Dimensions: (time: 1, space: 1)
Coordinates:
* time (time) datetime64[ns] 2000-01-01
* space (space) <U2 'IA'
Data variables:
foo (time, space) float64 0.1294"""
ds.sel(time="2000-01-01")
"""Out[24]:
<xarray.Dataset>
Dimensions: (space: 3)
Coordinates:
time datetime64[ns] 2000-01-01
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
foo (space) float64 0.1294 0.8599 0.8204"""
不支持对数据集进行位置索引,因为数据集中维度的顺序有些不明确(不同的数组之间会有所不同)。但是,您可以使用维名称进行常规索引:
ds[dict(space=[0], time=[0])]
"""Out[25]:
<xarray.Dataset>
Dimensions: (time: 1, space: 1)
Coordinates:
* time (time) datetime64[ns] 2000-01-01
* space (space) <U2 'IA'
Data variables:
foo (time, space) float64 0.1294"""
ds.loc[dict(time="2000-01-01")]
"""Out[26]:
<xarray.Dataset>
Dimensions: (space: 3)
Coordinates:
time datetime64[ns] 2000-01-01
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
foo (space) float64 0.1294 0.8599 0.8204"""
Dropping labels and dimensions
drop_sel()方法返回一个新对象,其中列出了沿已删除维度的索引标签:
ds.drop_sel(space=["IN", "IL"])
"""Out[27]:
<xarray.Dataset>
Dimensions: (time: 4, space: 1)
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA'
Data variables:
foo (time, space) float64 0.1294 0.3521 0.5948 0.2355"""
使用drop_dims()从数据集中删除完整的维度。具有这些维度的任何变量也会被删除:
ds.drop_dims("time")
"""Out[28]:
<xarray.Dataset>
Dimensions: (space: 3)
Coordinates:
* space (space) <U2 'IA' 'IL' 'IN'
Data variables:
*empty*"""
Masking with where
xarray对象上的索引方法通常返回原始数据的子集。但是,有时选择与原始数据具有相同形状但某些元素被遮罩的对象会很有用。要在xarray中进行这种类型的选择,请使用where():
da = xr.DataArray(np.arange(16).reshape(4, 4), dims=["x", "y"])
da.where(da.x + da.y < 4)
"""Out[30]:
<xarray.DataArray (x: 4, y: 4)>
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., nan],
[ 8., 9., nan, nan],
[12., nan, nan, nan]])
Dimensions without coordinates: x, y"""
默认情况下,保持数据的原始大小。对于所选数据大小远小于原始数据的情况,使用选项drop=True会裁剪完全遮罩的坐标元素:
da.where(da.y < 2, drop=True)
"""Out[32]:
<xarray.DataArray (x: 4, y: 2)>
array([[ 0., 1.],
[ 4., 5.],
[ 8., 9.],
[12., 13.]])
Dimensions without coordinates: x, y"""
Selecting values with isin
若要检查xarray对象的元素是否包含单个对象,可以使用等号运算符==(例如,arr == 3)进行比较。要检查多个值,请使用isin():
da = xr.DataArray([1, 2, 3, 4, 5], dims=["x"])
"""da.isin([2, 4])
Out[34]:
<xarray.DataArray (x: 5)>
array([False, True, False, True, False])
Dimensions without coordinates: x"""
isin()特别适合与where()配合使用,以支持按尚未成为数组标签的数组进行索引:
lookup = xr.DataArray([-1, -2, -3, -4, -5], dims=["x"])
da.where(lookup.isin([-2, -4]), drop=True)
"""Out[36]:
<xarray.DataArray (x: 2)>
array([2., 4.])
Dimensions without coordinates: x"""
但是,需要注意的是:当重复执行时,这种类型的索引比使用sel()要慢得多。
Vectorized Indexing
像numpy和pandas一样,xarray支持以矢量化的方式一次索引许多数组元素。 如果只提供整数、切片或无标签数组(
没有维度名的数组,如np.ndarray、list,而不是DataArray()或Variable())
索引可以理解为正交。每个索引器组件沿着相应的维独立选择,类似于矢量索引在Fortran或MATLAB中的工作方式,或者在使用numpy.ix_()
帮助器之后:
da = xr.DataArray(
np.arange(12).reshape((3, 4)),
dims=["x", "y"],
coords={"x": [0, 1, 2], "y": ["a", "b", "c", "d"]},
)
da
"""Out[38]:
<xarray.DataArray (x: 3, y: 4)>
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Coordinates:
* x (x) int64 0 1 2
* y (y) <U1 'a' 'b' 'c' 'd'
"""
da[[0, 2, 2], [1, 3]]
"""Out[39]:
<xarray.DataArray (x: 3, y: 2)>
array([[ 1, 3],
[ 9, 11],
[ 9, 11]])
Coordinates:
* x (x) int64 0 2 2
* y (y) <U1 'b' 'd'"""
为了更加灵活,您可以提供DataArray()对象作为索引器。结果数组的维数由索引器维数的有序并集给出:
ind_x = xr.DataArray([0, 1], dims=["x"])
ind_y = xr.DataArray([0, 1], dims=["y"])
da[ind_x, ind_y] # orthogonal indexing
"""Out[42]:
<xarray.DataArray (x: 2, y: 2)>
array([[0, 1],
[4, 5]])
Coordinates:
* x (x) int64 0 1
* y (y) <U1 'a' 'b'"""
没有命名维度的切片或序列/数组被视为具有相同的维度,其索引如下:
# Because [0, 1] is used to index along dimension 'x',
# it is assumed to have dimension 'x'
da[[0, 1], ind_x]
"""Out[43]:
<xarray.DataArray (x: 2)>
array([0, 5])
Coordinates:
* x (x) int64 0 1
y (x) <U1 'a' 'b'"""
此外,您可以使用多维DataArray()作为索引器,其中生成的数组维数也由索引器的维数决定:
ind = xr.DataArray([[0, 1], [0, 1]], dims=["a", "b"])
da[ind]
"""Out[45]:
<xarray.DataArray (a: 2, b: 2, y: 4)>
array([[[0, 1, 2, 3],
[4, 5, 6, 7]],
[[0, 1, 2, 3],
[4, 5, 6, 7]]])
Coordinates:
x (a, b) int64 0 1 0 1
* y (y) <U1 'a' 'b' 'c' 'd'
Dimensions without coordinates: a, b"""
矢量化索引也适用于isel、loc和sel:
ind = xr.DataArray([[0, 1], [0, 1]], dims=["a", "b"])
da.isel(y=ind) # same as da[:, ind]
"""Out[47]:
<xarray.DataArray (x: 3, a: 2, b: 2)>
array([[[0, 1],
[0, 1]],
[[4, 5],
[4, 5]],
[[8, 9],
[8, 9]]])
Coordinates:
* x (x) int64 0 1 2
y (a, b) <U1 'a' 'b' 'a' 'b'
Dimensions without coordinates: a, b"""
ind = xr.DataArray([["a", "b"], ["b", "a"]], dims=["a", "b"])
da.loc[:, ind] # same as da.sel(y=ind)
"""Out[49]:
<xarray.DataArray (x: 3, a: 2, b: 2)>
array([[[0, 1],
[1, 0]],
[[4, 5],
[5, 4]],
[[8, 9],
[9, 8]]])
Coordinates:
* x (x) int64 0 1 2
y (a, b) <U1 'a' 'b' 'b' 'a'
Dimensions without coordinates: a, b"""
这些方法也可以应用于数据集对象
ds = da.to_dataset(name="bar")
ds.isel(x=xr.DataArray([0, 1, 2], dims=["points"]))
"""Out[51]:
<xarray.Dataset>
Dimensions: (points: 3, y: 4)
Coordinates:
x (points) int64 0 1 2
* y (y) <U1 'a' 'b' 'c' 'd'
Dimensions without coordinates: points
Data variables:
bar (points, y) int64 0 1 2 3 4 5 6 7 8 9 10 11"""
矢量化索引可用于从感兴趣的最近的网格单元中提取信息,例如,离指定气象站纬度和经度集合最近的气候模型网格单元。要触发矢量化索引行为,您需要为选择维度提供一个新的共享输出维度名称。在下面的示例中,选择的最接近的纬度和经度被重命名为名为“points”的输出维度:
ds = xr.tutorial.open_dataset("air_temperature")
# Define target latitude and longitude (where weather stations might be)
target_lon = xr.DataArray([200, 201, 202, 205], dims="points")
target_lat = xr.DataArray([31, 41, 42, 42], dims="points")
# Retrieve data at the grid cells nearest to the target latitudes and longitudes
da = ds["air"].sel(lon=target_lon, lat=target_lat, method="nearest")
da
"""Out[56]:
<xarray.DataArray 'air' (time: 2920, points: 4)>
[11680 values with dtype=float32]
Coordinates:
lat (points) float32 30.0 40.0 42.5 42.5
lon (points) float32 200.0 200.0 202.5 205.0
* time (time) datetime64[ns] 2013-01-01 ... 2014-12-31T18:00:00
Dimensions without coordinates: points
Attributes:
long_name: 4xDaily Air temperature at sigma level 995
units: degK
precision: 2
GRIB_id: 11
GRIB_name: TMP
var_desc: Air temperature
dataset: NMC Reanalysis
level_desc: Surface
statistic: Individual Obs
parent_stat: Other
actual_range: [185.16 322.1 ]"""
Assigning values with indexing
若要选择DataArray()的一部分并为其赋值,可以使用.loc():
ds = xr.tutorial.open_dataset("air_temperature")
ds["empty"] = xr.full_like(ds.air.mean("time"), fill_value=0)
ds["empty"].loc[dict(lon=260, lat=30)] = 100
lc = ds.coords["lon"]
la = ds.coords["lat"]
ds["empty"].loc[
dict(lon=lc[(lc > 220) & (lc < 260)], lat=la[(la > 20) & (la < 60)])
] = 100
# 或者用 where()
# modify one grid point using xr.where()
ds["empty"] = xr.where(
(ds.coords["lat"] == 20) & (ds.coords["lon"] == 260), 100, ds["empty"]
)
# or modify a 2D region using xr.where()
mask = (
(ds.coords["lat"] > 20)
& (ds.coords["lat"] < 60)
& (ds.coords["lon"] > 220)
& (ds.coords["lon"] < 260)
)
ds["empty"] = xr.where(mask, 100, ds["empty"])
矢量化索引也可用于为xarray对象赋值
da = xr.DataArray(
np.arange(12).reshape((3, 4)),
dims=["x", "y"],
coords={"x": [0, 1, 2], "y": ["a", "b", "c", "d"]},
)
da
"""Out[67]:
<xarray.DataArray (x: 3, y: 4)>
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Coordinates:
* x (x) int64 0 1 2
* y (y) <U1 'a' 'b' 'c' 'd'"""
da[0] = -1 # assignment with broadcasting
da
"""Out[69]:
<xarray.DataArray (x: 3, y: 4)>
array([[-1, -1, -1, -1],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Coordinates:
* x (x) int64 0 1 2
* y (y) <U1 'a' 'b' 'c' 'd'"""
ind_x = xr.DataArray([0, 1], dims=["x"])
ind_y = xr.DataArray([0, 1], dims=["y"])
da[ind_x, ind_y] = -2 # assign -2 to (ix, iy) = (0, 0) and (1, 1)
da
"""Out[73]:
<xarray.DataArray (x: 3, y: 4)>
array([[-2, -2, -1, -1],
[-2, -2, 6, 7],
[ 8, 9, 10, 11]])
Coordinates:
* x (x) int64 0 1 2
* y (y) <U1 'a' 'b' 'c' 'd'"""
da[ind_x, ind_y] += 100 # increment is also possible
da
"""Out[75]:
<xarray.DataArray (x: 3, y: 4)>
array([[98, 98, -1, -1],
[98, 98, 6, 7],
[ 8, 9, 10, 11]])
Coordinates:
* x (x) int64 0 1 2
* y (y) <U1 'a' 'b' 'c' 'd'"""
注意:
da = xr.DataArray([0, 1, 2, 3], dims=["x"])
ind = xr.DataArray([0, 0, 0], dims=["x"])
da[ind] -= 1
da
"""Out[79]:
<xarray.DataArray (x: 4)>
array([-1, 1, 2, 3])
Dimensions without coordinates: x"""
这是因为其中第0个元素只减1一次。这是因为调用了三次v[0] = v[0] - 1,而不是v[0] = v[0] - 1 - 1 - 1。
使用任何索引方法isel或sel时,不要试图赋值
DO NOT do this
da.isel(space=0) = 0
相反,可以使用基于字典的索引来分配值:
da[dict(space=0)] = 0
使用链式索引赋值。sel or。isel默默失败。
da = xr.DataArray([0, 1, 2, 3], dims=["x"])
# DO NOT do this
da.isel(x=[0, 1, 2])[1] = -1
da
"""Out[82]:
<xarray.DataArray (x: 4)>
array([0, 1, 2, 3])
Dimensions without coordinates: x"""
您也可以一次为数据集的所有变量赋值:
ds_org = xr.tutorial.open_dataset("eraint_uvz").isel(
latitude=slice(56, 59), longitude=slice(255, 258), level=0
)
# set all values to 0
ds = xr.zeros_like(ds_org)
ds
"""Out[85]:
<xarray.Dataset>
Dimensions: (month: 2, latitude: 3, longitude: 3)
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Data variables:
z (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 0.0
u (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 0.0
v (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 0.0
Attributes:
Conventions: CF-1.0
Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m..."""
# by integer
ds[dict(latitude=2, longitude=2)] = 1
ds["u"]
"""Out[87]:
<xarray.DataArray 'u' (month: 2, latitude: 3, longitude: 3)>
array([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 1.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 1.]]])
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Attributes:
number_of_significant_digits: 2
units: m s**-1
long_name: U component of wind
standard_name: eastward_wind"""
ds["v"]
"""Out[88]:
<xarray.DataArray 'v' (month: 2, latitude: 3, longitude: 3)>
array([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 1.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 1.]]])
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Attributes:
number_of_significant_digits: 2
units: m s**-1
long_name: V component of wind
standard_name: northward_wind"""
# by label
ds.loc[dict(latitude=47.25, longitude=[11.25, 12])] = 100
ds["u"]
"""Out[90]:
<xarray.DataArray 'u' (month: 2, latitude: 3, longitude: 3)>
array([[[ 0., 0., 0.],
[100., 100., 0.],
[ 0., 0., 1.]],
[[ 0., 0., 0.],
[100., 100., 0.],
[ 0., 0., 1.]]])
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Attributes:
number_of_significant_digits: 2
units: m s**-1
long_name: U component of wind
standard_name: eastward_wind"""
# dataset as new values
new_dat = ds_org.loc[dict(latitude=48, longitude=[11.25, 12])]
new_dat
"""Out[92]:
<xarray.Dataset>
Dimensions: (longitude: 2, month: 2)
Coordinates:
* longitude (longitude) float32 11.25 12.0
latitude float32 48.0
level int32 200
* month (month) int32 1 7
Data variables:
z (month, longitude) float64 1.136e+05 1.136e+05 ... 1.187e+05
u (month, longitude) float64 12.75 12.69 14.87 14.62
v (month, longitude) float64 -7.891 -7.781 -1.875 -1.984
Attributes:
Conventions: CF-1.0
Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m..."""
ds.loc[dict(latitude=47.25, longitude=[11.25, 12])] = new_dat
ds["u"]
"""Out[94]:
<xarray.DataArray 'u' (month: 2, latitude: 3, longitude: 3)>
array([[[ 0. , 0. , 0. ],
[12.75 , 12.687, 0. ],
[ 0. , 0. , 1. ]],
[[ 0. , 0. , 0. ],
[14.875, 14.625, 0. ],
[ 0. , 0. , 1. ]]])
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Attributes:
number_of_significant_digits: 2
units: m s**-1
long_name: U component of wind
standard_name: eastward_wind"""
More advanced indexing
使用DataArray()对象作为索引器可以实现非常灵活的索引。以下是逐点索引的一个示例:
da = xr.DataArray(np.arange(56).reshape((7, 8)), dims=["x", "y"])
da
"""Out[96]:
<xarray.DataArray (x: 7, y: 8)>
array([[ 0, 1, 2, ..., 5, 6, 7],
[ 8, 9, 10, ..., 13, 14, 15],
[16, 17, 18, ..., 21, 22, 23],
...,
[32, 33, 34, ..., 37, 38, 39],
[40, 41, 42, ..., 45, 46, 47],
[48, 49, 50, ..., 53, 54, 55]])
Dimensions without coordinates: x, y
da.isel(x=xr.DataArray([0, 1, 6], dims="z"), y=xr.DataArray([0, 1, 0], dims="z"))
Out[97]:
<xarray.DataArray (z: 3)>
array([ 0, 9, 48])
Dimensions without coordinates: z"""
其中在(ix,iy) = ((0,0),(1,1),(6,0))的三个元素被选择并且沿着新的维度z被映射
如果要向新维度z添加坐标,可以提供带有坐标的DataArray
da.isel(
x=xr.DataArray([0, 1, 6], dims="z", coords={"z": ["a", "b", "c"]}),
y=xr.DataArray([0, 1, 0], dims="z"),
)
"""Out[98]:
<xarray.DataArray (z: 3)>
array([ 0, 9, 48])
Coordinates:
* z (z) <U1 'a' 'b' 'c'"""
类似地,基于标签的逐点索引也可以通过。sel方法
da = xr.DataArray(
np.random.rand(4, 3),
[
("time", pd.date_range("2000-01-01", periods=4)),
("space", ["IA", "IL", "IN"]),
],
)
times = xr.DataArray(
pd.to_datetime(["2000-01-03", "2000-01-02", "2000-01-01"]), dims="new_time"
)
da.sel(space=xr.DataArray(["IA", "IL", "IN"], dims=["new_time"]), time=times)
"""Out[101]:
<xarray.DataArray (new_time: 3)>
array([0.92, 0.34, 0.59])
Coordinates:
time (new_time) datetime64[ns] 2000-01-03 2000-01-02 2000-01-01
space (new_time) <U2 'IA' 'IL' 'IN'
* new_time (new_time) datetime64[ns] 2000-01-03 2000-01-02 2000-01-01"""
Align and reindex
Xarray的reindex、reindex_like和align将DataArray或Dataset强加到与维度相对应的一组新坐标上。原始值是仍然在新标签中找到的索引标签的子集,并且用NaN填充对应于在原始对象中没有找到的新标签的值。
组合多个对象的Xarray操作通常会自动对齐它们的参数以共享相同的索引。然而,手动校准对于更好的控制和提高性能是有用的。
要重新索引特定维度,请使用reindex():
da.reindex(space=["IA", "CA"])
"""Out[102]:
<xarray.DataArray (time: 4, space: 2)>
array([[0.574, nan],
[0.245, nan],
[0.92 , nan],
[0.754, nan]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'CA'"""
reindex_like()方法是一个有用的快捷方式。为了进行演示,我们将使用新值创建一个子集DataArray:
foo = da.rename("foo")
baz = (10 * da[:2, :2]).rename("baz")
baz
"""Out[105]:
<xarray.DataArray 'baz' (time: 2, space: 2)>
array([[5.74 , 0.613],
[2.453, 3.404]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL'"""
用baz重新索引foo会沿着每个维度选择出前两个值:
foo.reindex_like(baz)
"""Out[106]:
<xarray.DataArray 'foo' (time: 2, space: 2)>
array([[0.574, 0.061],
[0.245, 0.34 ]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL'"""
相反的操作要求我们重新索引到一个更大的形状,所以我们用NaN填充缺少的值:
baz.reindex_like(foo)
"""Out[107]:
<xarray.DataArray 'baz' (time: 4, space: 3)>
array([[5.74 , 0.613, nan],
[2.453, 3.404, nan],
[ nan, nan, nan],
[ nan, nan, nan]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'"""
align()函数使我们能够执行更灵活的类似数据库的“内”、“外”、“左”和“右”连接:
xr.align(foo, baz, join="inner")
"""Out[108]:
(<xarray.DataArray 'foo' (time: 2, space: 2)>
array([[0.574, 0.061],
[0.245, 0.34 ]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL',
<xarray.DataArray 'baz' (time: 2, space: 2)>
array([[5.74 , 0.613],
[2.453, 3.404]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02
* space (space) <U2 'IA' 'IL')"""
xr.align(foo, baz, join="outer")
"""Out[109]:
(<xarray.DataArray 'foo' (time: 4, space: 3)>
array([[0.574, 0.061, 0.59 ],
[0.245, 0.34 , 0.985],
[0.92 , 0.038, 0.862],
[0.754, 0.405, 0.344]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN',
<xarray.DataArray 'baz' (time: 4, space: 3)>
array([[5.74 , 0.613, nan],
[2.453, 3.404, nan],
[ nan, nan, nan],
[ nan, nan, nan]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN')"""
reindex_like和align在DataArray和Dataset对象之间可以互换使用,并且可以使用任意数量的匹配维度名称:
ds
"""Out[110]:
<xarray.Dataset>
Dimensions: (month: 2, latitude: 3, longitude: 3)
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Data variables:
z (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
u (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
v (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
Attributes:
Conventions: CF-1.0
Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m..."""
ds.reindex_like(baz)
"""Out[111]:
<xarray.Dataset>
Dimensions: (month: 2, latitude: 3, longitude: 3)
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Data variables:
z (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
u (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
v (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
Attributes:
Conventions: CF-1.0
Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m..."""
other = xr.DataArray(["a", "b", "c"], dims="other")
# this is a no-op, because there are no shared dimension names
ds.reindex_like(other)
"""Out[113]:
<xarray.Dataset>
Dimensions: (month: 2, latitude: 3, longitude: 3)
Coordinates:
* longitude (longitude) float32 11.25 12.0 12.75
* latitude (latitude) float32 48.0 47.25 46.5
level int32 200
* month (month) int32 1 7
Data variables:
z (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
u (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
v (month, latitude, longitude) float64 0.0 0.0 0.0 ... 0.0 0.0 1.0
Attributes:
Conventions: CF-1.0
Info: Monthly ERA-Interim data. Downloaded and edited by fabien.m..."""
Missing coordinate labels
每个维度的坐标标签是可选的(从xarray v0.9开始)。基于标签的索引。sel和。loc使用基于整数的标准位置索引作为没有坐标标签的尺寸的备用索引
da = xr.DataArray([1, 2, 3], dims="x")
"""da.sel(x=[0, -1])
Out[115]:
<xarray.DataArray (x: 2)>
array([1, 3])
Dimensions without coordinates: x"""
如果一个或两个对象都没有坐标标签,则xarray对象之间的对齐只有在同名的所有尺寸都具有相同长度时才会成功。否则,它会引发一个信息性错误
Underlying Indexes
Xarray利用pandas内部索引以执行索引操作。如果需要访问底层索引,可以通过indexes属性获得它们。
da = xr.DataArray(
np.random.rand(4, 3),
[
("time", pd.date_range("2000-01-01", periods=4)),
("space", ["IA", "IL", "IN"]),
],
)
da
"""Out[118]:
<xarray.DataArray (time: 4, space: 3)>
array([[0.171, 0.395, 0.642],
[0.275, 0.462, 0.871],
[0.401, 0.611, 0.118],
[0.702, 0.414, 0.342]])
Coordinates:
* time (time) datetime64[ns] 2000-01-01 2000-01-02 2000-01-03 2000-01-04
* space (space) <U2 'IA' 'IL' 'IN'"""
da.indexes
"""Out[119]:
Indexes:
time DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[ns]', name='time', freq='D')
space Index(['IA', 'IL', 'IN'], dtype='object', name='space')"""
da.indexes["time"]
"""Out[120]: DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04'], dtype='datetime64[ns]', name='time', freq='D')"""
使用get_index()获取一个维度的索引,回到默认的pandas.RangeIndex,如果没有坐标标签:
da = xr.DataArray([1, 2, 3], dims="x")
da
"""Out[122]:
<xarray.DataArray (x: 3)>
array([1, 2, 3])
Dimensions without coordinates: x"""
da.get_index("x")
#Out[123]: RangeIndex(start=0, stop=3, step=1, name='x')
Copies vs. Views
数组索引是返回基础数据的视图还是副本取决于标签的性质。
- 对于位置(整数)索引,xarray遵循与NumPy相同的规则:
- 只有整数和切片的位置索引返回一个视图。
- 数组或列表的位置索引返回一个副本。
- 基于标签的索引规则更加复杂:
- 仅使用切片的基于标签的索引返回一个视图。
- 基于标签的数组索引返回一个副本。
- 基于标签的标量索引返回一个视图或一个副本,这取决于相应的位置索引器是表示为整数还是切片对象。具体规则由pandas决定。
与pandas相比,xarray中的数据是副本还是视图更容易预测,因此与pandas不同,xarray不会产生带有副本警告的设置。但是,您仍然应该避免使用链式索引进行赋值。
Multi-level indexing
就像pandas一样,使用loc和sel可以对多级索引进行高级索引。您可以通过提供多个索引器对多索引进行切片,即切片元组、标签、标签列表或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
"""Out[126]:
<xarray.DataArray (x: 6, y: 3)>
array([[0.596, 0.2 , 0.1 ],
[0.735, 0.017, 0.481],
[0.096, 0.497, 0.839],
[0.897, 0.733, 0.759],
[0.561, 0.471, 0.139],
[0.094, 0.942, 0.134]])
Coordinates:
* x (x) object MultiIndex
* one (x) object 'a' 'a' 'b' 'b' 'c' 'c'
* two (x) int64 0 1 0 1 0 1
* y (y) int64 0 1 2"""
mda.sel(x=(list("ab"), [0]))
"""Out[127]:
<xarray.DataArray (x: 2, y: 3)>
array([[0.596, 0.2 , 0.1 ],
[0.096, 0.497, 0.839]])
Coordinates:
* x (x) object MultiIndex
* one (x) object 'a' 'b'
* two (x) int64 0 0
* y (y) int64 0 1 2"""
您还可以通过提供标签或元组列表或元组切片来选择多个元素:
mda.sel(x=[("a", 0), ("b", 1)])
"""Out[128]:
<xarray.DataArray (x: 2, y: 3)>
array([[0.596, 0.2 , 0.1 ],
[0.897, 0.733, 0.759]])
Coordinates:
* x (x) object MultiIndex
* one (x) object 'a' 'b'
* two (x) int64 0 1
* y (y) int64 0 1 2"""
此外,xarray支持字典
mda.sel(x={"one": "a", "two": 0})
"""Out[129]:
<xarray.DataArray (y: 3)>
array([0.596, 0.2 , 0.1 ])
Coordinates:
x object ('a', 0)
one <U1 'a'
two int64 0
* y (y) int64 0 1 2"""
为了方便起见,sel还直接接受多索引级别作为关键字参数
mda.sel(one="a", two=0)
"""Out[130]:
<xarray.DataArray (y: 3)>
array([0.596, 0.2 , 0.1 ])
Coordinates:
x object ('a', 0)
one <U1 'a'
two int64 0
* y (y) int64 0 1 2"""
请注意,使用sel不可能将维度索引器与该维度的级别索引器混合使用(例如,mda.sel(x={‘one’: ‘a’},two=0)将引发ValueError)。
像pandas一样,xarray处理多索引上的部分选择(级别下降)。如下所示,当多索引减少为单索引时,它还会重命名维度/坐标。
mda.loc[{"one": "a"}, ...]
"""Out[131]:
<xarray.DataArray (two: 2, y: 3)>
array([[0.596, 0.2 , 0.1 ],
[0.735, 0.017, 0.481]])
Coordinates:
* two (two) int64 0 1
* y (y) int64 0 1 2
one <U1 'a'"""
与pandas不同,xarray在一些不明确的情况下使用loc时不会猜测您是否提供了索引级别或维度。例如,对于mda.loc[{‘one’: ‘a ‘,’ two’: 0}]和mda.loc['a ‘,0] xarray总是将(’ one ‘,’ two ‘)和(’ a ',0)分别解释为第一维和第二维的名称和标签。您必须指定所有维度或在loc说明符中使用省略号,例如,在上面的示例中,mda.loc[{‘one’: ‘a ‘,’ two’: 0},:]或mda.loc[('a ',0),…].
Indexing rules
这里我们描述xarray用于矢量化索引的完整规则。注意,这是出于解释的目的:为了提高效率和支持各种后端,实际实现是不同的。
- (仅适用于基于标签的索引。)从相应的pandas.Index沿着每个维度查找位置索引
- 完整切片对象:在没有索引器的情况下为每个维度插入。
- 切片对象转换成数组,由NP . arange(* slice . indexes(…))
- 假设没有维度的数组索引器的维度名称来自要索引的维度,如np.ndarray和list。例如,v.isel(x=[0,1])被理解为v.isel(x=xr。DataArray([0,1],dims=[‘x’]))。
- 对于Dataset或DataArray中的每个变量(数组及其坐标):
- 根据维名称广播所有相关索引器(有关完整的详细信息,请参见按维名称广播)。
- 使用NumPy的高级索引规则,通过广播索引器对下划线数组进行索引。
- 如果任何索引器数据数组具有坐标,但不存在同名的坐标,则将它们附加到索引对象。