Xarray - 数据对象

本文主要介绍 Xarray 的数据对象( DataArray 和 DataSet )相关的内容,包括数据对象的创建、读写、索引和插值等操作

1
2
3
4
5
6
import numpy as np
import xarray as xr
import pandas as pd
from matplotlib import pyplot as plt
%matplotlib inline
rng = np.random.default_rng(seed=0) # 给一个随机数种子,使得每次运行得到的随机数是相同的

创建xarray对象

Xarray 包提供了两种数据储存结构: DataArray 类Dataset 类

  • DataArray 将维度名称,坐标和属性添加到多维数组
  • Dataset 则是多个 DataArray 数组的集合

DataArray

DataArray 是一个容器,装一个变量的信息,比如可以把温度在时空的变化放在里面

xr.DataArray( data, dims, name, coords, attrs )

添加数据、维度名称和数组名称

可以注意到 xr.DataArray( ) 括号内的三行内容:

  • data : 利用 Numpy 包的 np.ones 函数创建一个 2x6x6 numpy 类的全1数组
  • dims : 把三个维度分别命名为 time, lon, lat
  • name : 取了一个名字 Temperature Data
1
2
3
4
5
6
da = xr.DataArray(
np.ones((2, 7, 13)), # 温度数据
dims = ("time", "lat", "lon"), # 维度名称
name = "Temperature Data" # 数组名称
)
da

添加坐标信息

对坐标数据而言,是用 coords = { } 大括号框定的区域。

"longtitude" : ( "lon", np.arange(0, 181, 30) ) 中 :

  • "longtitude" 是坐标名称,
  • "lon" 是坐标名称对应的维度,
  • np.arange(0, 181, 30) 是维度 "lon" 对应坐标数据
1
2
3
4
5
6
7
8
9
10
11
12
da = xr.DataArray(
np.ones((2, 7, 13)), # 温度数据
dims=("time", "lat", "lon"), # 维度名称
name="Temperature Data", # 数组名称
# 坐标属性
coords={
"longtitude": ("lon", np.linspace(0, 360, 13)),
"latitude": ("lat", np.linspace(-90, 90, 7)),
"time": ("time", ['2021-01-01','2021-01-02'])
}
)
da

添加数据属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
da = xr.DataArray(
np.ones((2, 7, 13)), # 温度数据
dims=("time", "lat", "lon"), # 维度名称
name="Temperature Data", # 数组名称
# 坐标属性
coords={
"longtitude": ("lon", np.linspace(0, 360, 13)),
"latitude": ("lat", np.linspace(-90, 90, 7)),
"time": ("time", ['2021-01-01','2021-01-02'])
},
# 属性
attrs={
"Autor": "WANG BJ",
"FillValue": -9999
}
)
da

添加坐标属性

有时候坐标参数(如经纬度)需要附加一些信息, 例如可以附加经纬度的单位(degree)

添加坐标参数属性的方法即在坐标值的后面添加上一个 大括号 { "属性": value } 括好的数据,
如:"latitude":("lon",np.arange(0, 361, 30), {"unit": "degree"}) ,冒号的左侧为属性名称,右侧为对应的值。

对于多个属性的添加,需用 逗号 进行间隔,如 {"step": "5 degree","first value":1}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
da = xr.DataArray(
np.ones((2, 7, 13)), # 温度数据
dims=("time", "lat", "lon"), # 维度名称
name="Temperature Data", # 数组名称
# 坐标属性
coords={
"longtitude": ("lon", np.linspace(0, 360, 13), {"unit": "degree"}), # 添加坐标属性
"latitude": ("lat", np.linspace(-90, 90, 7), {"unit": "degree"}), # 添加坐标属性
"time": ("time", ['2021-01-01','2021-01-02'])
},
# 属性
attrs={
"Autor": "WANG BJ",
"FillValue": -9999
}
)
da

提取数据、维度、坐标和属性信息

提取 da 数据 ( data ) :

1
da.data

提取 da 维度名称 ( dimensions ) :

1
da.dims

提取 da 坐标信息 ( coordinates ) :

1
da.coords

提取 da 属性 ( attributes ) :

1
da.attrs

练习 - 1

现已通过随机函数常见了一个名为 height 伪数据

1.不考虑创建的其他要素,试着以 height 为基础数据创建一个 DataArray 对象。下面提供了部分代码。

2.添加维度名字“x”和“y”。

3.添加数组名称“My random array”

4.分别对“x”和“y”维度添加坐标“longtitude”(经度)和“latitude”(纬度)。;经度从-180至180,步长为1;纬度从-90至90,步长为1。

1
2
3
4
5
6
7
8
9
10
11
height = rng.random((180, 360)) * 400
# 在这里写你的代码
xr.DataArray(
height,
dims=("y", "x"),
name="My random array",
coords={
"longtitude": ("x", np.linspace(1, 360, 360), {"steps": 1}),
"latitude": ("y", np.linspace(-89.5, 89.5, 180), {"steps": 1})
}
)

Dataset

xr.Dataset( data_vars, coords, attrs )

Dataset 的对象可以将 多个变量 放在一起。可以定义每一个变量都有相应不同维度。

Dataset 由下列三个部分组成

  • data_vars :变量信息, "var":(dims,data,{"attr":value}) / "var":DataArray
  • coords :坐标信息
  • attrs :属性信息

添加变量、坐标和属性

data_vars 的大括号 { "var": (dims, data, {"属性": value}) } 中包含了 ab 两个变量,变量名后以小括号扩住这个变量的信息。小括号的信息包含下列信息

  • 维度 :在命名维度名称的同时,也就确定了维度的大小。例子中包含两个维度x和y。
  • 数据 :数据大小的确定根据维度的大小所决定。例子中是利用np.ones函数构建了一个3×4的全1矩阵,利用np.full函数构建项数为8全为3的一维数组。
  • 属性 :用大括号包含。写法:名称字符串+冒号:+属性值字符串。不同属性之间用逗号间隔,类似于 {"atrri1": "First", "atrri2": "Second"}

coords 的大括号包含了具体的坐标参数。与 DataArray 类似。要确保维度名称代表的数据的数目和坐标参数的数目相一致。

attrs 的大括号包含了属性参数。与 DataArray 类似。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ds = xr.Dataset(
data_vars={
"a": (("x", "y"), np.ones((3, 4))), # 变量名: (维度, 数据)
"b": ("t", np.full(8, 3), {"b_atrri": "b_value"}),# 变量名: (维度, 数据,属性)
},
coords={
"longtitude":("x",[-1, 0, 1]), # 维度名称: (维度, 维度范围)
"latitude":("y",[-1, 0, 1, 2]),
"time":("t",[
"2021-01-01", "2021-01-02", "2021-01-03", "2021-01-04",
"2021-01-05", "2021-01-06", "2021-01-07", "2021-01-08"
])
},
attrs={"Dataset attr": "Num1"}
)
ds

创建同一维度上但多个变量的坐标参数不一致的 Dataset

如果要创建一些在同一个坐标(Coordinates)上但坐标变量不一致的变量,我们不能采用简化的语法。
相反,我们需要使用到 DataArray 对象: data_vars = { "var": DataArray }

1
2
3
4
5
6
7
x_a = np.arange(1, 4)
x_b = np.arange(-1, 3)

a = xr.DataArray(np.linspace(0, 1, 3), dims="x", coords={"x": x_a})
b = xr.DataArray(np.zeros(4), dims="x", coords={"x": x_b})

xr.Dataset(data_vars={"a": a, "b": b})

练习 - 2

1.利用两个 DataArray 创建一个具有 heightgravity_anomaly 两个变量且具有 xy 两个维度的 Dataset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
height = rng.random((360, 180)) * 400
gravity_anomaly = rng.random((360, 180)) * 400 - 200

height_da = xr.DataArray(height,
dims=("x","y"))

gravity_anomaly_da = xr.DataArray(gravity_anomaly,
dims=("x","y"))

# 在这里写你的代码
xr.Dataset(
data_vars={
"height": height_da,
"gravity_anomaly": gravity_anomaly_da
}
)

2.在上题的基础上添加 latitudelongitude 两个坐标

  • longitude : 从 -180 至 180,步长为1(采用 np.linspace 函数)
  • latitude : 从 -90 至 90,步长为1
1
2
3
4
5
6
7
8
9
10
xr.Dataset(
data_vars={
"height": height_da,
"gravity_anomaly": gravity_anomaly_da
},
coords={ # 在这里写你的代码
"longitude": ("x", np.linspace(1, 360, 360)),
"latitude": ("y", np.linspace(-89.5, 89.5, 180))
}
)

3.添加属性到坐标(coordinates)和变量(variables):

  • latitude : "type": "geodetic"
  • longitude : "prime_meridian": "greenwich"
  • height : "ellipsoid": "wgs84"
  • gravity_anomaly : "ellipsoid": "grs80"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
height_da = xr.DataArray(height,
dims=("x","y"),
# 在这里写你的代码
attrs={
"ellipsoid": "wgs84"
}
)
gravity_anomaly_da = xr.DataArray(gravity_anomaly,
dims=("x","y"),
# 在这里写你的代码
attrs={
"ellipsoid": "grs80"
}
)
xr.Dataset(
data_vars={'height':height_da,
'gravity_anomaly':gravity_anomaly_da},
coords={'longtitude':('x',np.linspace(1,360,360), {"prime_meridian": "greenwich"}),# 在这里写你的代码
'latitude':('y',np.linspace(-89.5, 89.5,180), {"type": "geodetic"})# 在这里写你的代码
}
)

数据读取与转换

pandas 数据类型转换

pandas 对象转换为 xarray 对象:对 pandas 对象使用 to_xarray 方法

xarray 对象转为 pandas 对象:对 xarray 对象使用 to_pandas 方法

Series → xarray

Series.to_xarray()

若要将变量 series(pandas 类型)转为 xarray 类型只需在变量后加上 .to_xarray() 方法即可。

由于只有一个变量,所以转换的结果是 xarray 中的 DataArray 类型。

1
2
3
4
series = pd.Series(np.ones((10,)), index=list("abcdefghij"))
series
arr = series.to_xarray()
arr

DataArray → pandas

DataArray.to_pandas()

若要将 xarray 转为 pandas 类型,类似的在变量后加上 .to_pandas()

1
arr.to_pandas()

对于 xarray 的多变量 Dataset 对象同理可用类似对 pandas 对象的转换方法,只需要在对象后添加 to_series / to_dataframe 即可:

先创建一个 Dataset 对象 ds

1
2
3
4
5
6
7
ds = xr.Dataset(
data_vars={
"a": ("x", np.arange(5)),
"b": (("x", "y"), np.ones((5, 4)))
}
)
ds

DataArray → Series

DataArray.to_series()

将 ds(Dataset)中的变量 a 利用 .to_series() 转换为 pandas 中的 Series(列表)类型。
由于没有指定 index,则在默认情况下,index 默认为数字且从 0 开始,步长为 1.

1
ds.a.to_series()

如果要指定 index,则需在转换为 pandas 类型后,对 index 进行指定,比如

1
2
3
myseries = ds.a.to_series()
myseries.index=list("sylsy")
myseries

同理也可将 ds(Dataset)中的变量 b 转换为 pandas 类型,这里将 多维数据 使用 多层索引

1
ds.b, ds.b.to_series()

Dataset → DataFrame

Dataset.to_dataframe()

to_dataframe :将 DataArrayDataset 对象转换为 pandas.dataframe 。注意到 DataArray 对象名称与转换为数据框的名称一样都为 a

1
ds.a.to_dataframe()

为保证数据的连续性,对于转换为DataFrame数组会发生广播。
类似于转换为列表,为保证数据的连续性,对于转换为DataFrame数组也会发生广播。

1
ds.to_dataframe()

数据输入输出

Xarray 最广泛使用的特性之一是它读写各种数据格式的能力。例如,Xarray 可以读取以下格式:

  • NetCDF / GRIB (通过函数 open_dataset / open_mfdataset , to_netcdf / save_mfdataset )
  • Zarr (通过函数 open_zarr , to_zarr )
  • GeoTIFF / GDAL rasters (通过函数 open_rasterio )

NetCDF(Network Common Data Form)/ GRIB

Dataset.to_netcdf(path), DataArray.to_netcdf(path)
xr.open_dataset(path), xr.open_dataarray(path)

存储 Xarray 数据结构的推荐方法是 NetCDF(Network Common Data Form),这是一种二进制文件格式,用于起源于地球科学的自描述数据集。文件的后缀为.nc。Xarray 基于 netCDF 数据模型,因此磁盘上的 netCDF 文件直接对应于数据集对象。

Xarray 采用 open_dataset / open_dataarray 函数读取NetCDF 文件,采用 to_netcdf 方法将数据写入文件。

1
2
3
import xarray as xr
cma = xr.open_dataset(".data/cma.grib", engine="cfgrib")
cma

将 DataSets 和 DataArray 写入 nc 文件中

接下来首先创建一些数据集,并使用to_netcdf将数据写入硬盘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ds1 = xr.Dataset(
data_vars={
"a": (("x", "y"), np.random.randn(4, 2)),
"b": (("z", "x"), np.random.randn(6, 4)),
},
coords={
"x": np.arange(4),
"y": np.arange(-2, 0),
"z": np.arange(-3, 3),
},
)
ds2 = xr.Dataset(
data_vars={
"a": (("x", "y"), np.random.randn(7, 3)),
"b": (("z", "x"), np.random.randn(2, 7)),
},
coords={
"x": np.arange(6, 13),
"y": np.arange(3),
"z": np.arange(3, 5),
},
)
ds1
1
2
3
4
5
# DataSets写入文件
ds1.to_netcdf(".data/ds1.nc")
ds2.to_netcdf(".data/ds2.nc")
# DataArray写入文件
ds1.a.to_netcdf(".data/da1.nc")

读取 nc 文件

1
xr.open_dataset(".data/ds1.nc")
1
xr.open_dataarray(".data/da1.nc")

数据索引和分片

基于维度数字对数据进行索引和分片

引入:numpy 的索引和分片

获取 np_array 第一维度(axis0)索引为1和第二维度(axis1)索引为3 的值(维度默认索引起始值为0)

1
2
np_array = np.random.randn(3,4)
np_array[1,3]

当然也可以进行分片(slice),获取一范围数组的数据

1
np_array[:2,1:]

DataArray 的索引和分片

xarray.isel( dim1=loc1, dim2=loc2, ... )

xarray.isel( dim1=[ ... ], dim2=[ ... ], ... )

xarray.isel( dim1=slice( start, end ), dim2=slice( start, end ), ... )

方法 .isel(integer selection) 是一个基于维度名称数字索引的筛选的方法。

通过 .isel 这个方法筛选了 arr 第一维度x索引值为1和第二维度y索引值为3 的值。

1
2
arr = xr.DataArray(np_array, dims=("x","y"))
arr, arr.isel(x=[1,2], y=3)

xarray[ { "dim1": loc1, "dim2": loc2, "...": ... } ]

1
arr[{"x":1, "y":3}]

Dataset 的索引和切片

xarray.isel( dim1=loc1, dim2=loc2, ... )

xarray.isel( dim1=[ ... ], dim2=[ ... ], ... )

xarray.isel( dim1=slice( start, end ), dim2=slice( start, end ), ... )

对于这个 Dataset 的以 「维度名称数字分片」 需要使用 .isel 方法,同时对于各个维度用 slice 指定各个维度分片范围

这样的分片同时对 ds 中的变量 ab 均有分片作用

None 在代码中可以代替初始值或者末尾值。
x=slice(None,2) 等价为在numpy中的 [:2]y=slice(1,None) 等价为在numpy中的 [1:]

1
2
3
4
5
6
7
8
ds = xr.Dataset(
{
"a":(("x","y"), np.random.randn(3,4)),
"b":(("x","y"), np.random.randn(3,4))
}
)
# ds.isel(x=slice(None,2),y=slice(1,None))
ds.isel(x=[0,1])

其他索引方法:head, tail, thin

xarray.head( dim1, dim2, ... )

对于 .head() 方法,有以下的例子

方法 .head() 获得了 ds最左上角数据(首位, head) 到维度名称索引(x=2,y=3)的分片数据

1
2
display(ds)
display(ds.head(x=2,y=3))

xarray.tail( dim1, dim2, ... )

.head() 方法 相反.tail() 方法则是从维度名称索引(x=2,y=2)至 最右下角数据(尾部, tail) 的分片数据。

1
2
display(ds)
display(ds.tail(x=2,y=2))

xarray.thin( dim1, dim2, ... )

有时候我们需对原数据 缩小尺寸 ,不需要特别高精确度的数据。

通常的做法是给定一个 特定的步长按照这个步长进行取值
dim1 给定了在 dim1 方向上的筛选数据的步长, dim2 给定了在 dim2 方向上的筛选数据的步长。

1
2
display(ds)
display(ds.thin(x=2,y=3))

这样理解还是比较抽象,为便于理解这个函数的作用和意义,我们利用真实数据将原数组和缩小后的数组进行比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# import seaborn as sns
import numpy as np
import xarray as xr
import matplotlib.pyplot as plt

# 导入空气温度数据集
REALds = xr.open_dataset(".data/air_temperature.nc").isel(time=1)
# 获取2013-01-01T06:00:00空气温度数据
data = REALds.air
data_thin = REALds.air.thin(lat=3, lon=3)
# 绘制热力图
# sns.set()
# ax = sns.heatmap(data, center=0)
fig = plt.figure(figsize=(6, 8))
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)
data.plot(ax=ax1)
data_thin.plot(ax=ax2)
plt.subplots_adjust(hspace=0.3)

基于坐标值对数据进行索引和分片

xarray.sel( dim1=value1, dim2=value2, ... )

若要使用坐标名称筛选数据,可以使用类似于维度名称筛选数据的方法。
只是使用的是 .sel() 方法而非 .isel() 方法。

1
2
3
4
5
6
7
8
9
arr = xr.DataArray(
np.random.randint(0,10,(4,6)),
dims=("x","y"),
coords={
"x":[-3.2,2.1,5.3,6.5],
"y":pd.date_range("2009-01-05", periods=6, freq="M")
}
)
arr.sel(x=5.3, y="2009-04-30")

xarray.loc[ { "dim1": value1, "dim2": value2, "...": ... } ]

1
arr.loc[{"x":5.3, "y":"2009-04-30"}]

xarray.sel( dim1=value1, dim2=value2, ..., method )

上述的筛选方法需要指定特定的坐标数据。如果缺少特定的坐标数据(比如你忘记了具体的值,只知道大致的值),可以使用 method 参数进行指定选取你给的坐标最近 "nearest" 的坐标数据。

1
arr.sel(x=4, y="2009-04-01", method="nearest")

xarray.sel( dim1=[ ... ],dim2=[ ... ], ... )

xarray.sel( dim1=slice( start, end ), dim2=slice( start, end ), ... )

当然除此之外,不单单选取一个值,也可以选取多重数据

对于坐标x而言( "x":[-3.2,2.1,5.3,6.5] ),坐标的命名是 「离散」 的,因此在选取坐标x的时候需要进行 离散 选取。

对于坐标y时间而言( pd.date_range("2009-01-05", "2009-06-30", freq="M") ),产生数据的方法是 连续 的。
这种 「连续性数据」 多个筛选则需要通过 slice 函数进行选取

1
arr.sel(x=[-3.2, 6.5], y=slice("2009-04-01", "2009-05-31"))

xarray.drop_sel( dim1, dim2, ... )

如果我们仅仅是想要抛弃原数据中的一些部分,则可以用 drop_sel 筛选抛弃的部分,留下剩余的部分。

1
arr.drop_sel(x=[-3.2, 5.3])

练习 - 3

首先导入练习数据

1
2
ds = xr.open_dataset(".data/air_temperature.nc")
ds

1.筛选前30个纬度坐标且第20至40个经度坐标的数据

1
2
# 在这里写你的代码
ds.isel(lat=slice(None,30), lon=slice(20,40))

2.筛选北纬75度(75°N)且时间在2013年1月1日至2013年10月15日的数据

1
2
# 在这里写你的代码
ds.sel(lat=[75.0], time=slice("2013-01-01", "2013-10-01"))

3.去除经度260(100°W)至270(90°W)的值后的数据

1
2
# 在这里写你的代码
ds.drop_sel(lon=np.arange(260, 271, 2.5))

插值和广播

平面插值

xarray.interp( dim1, dim2, ..., method )

有时候想要知道格点框中更加高分辨率的值,这时候可以使用 interp 函数进行数据插值。

1
2
3
4
5
6
7
8
9
10
11
12
arr = xr.DataArray(
np.random.randn(4,6),
dims=("x","y"),
coords={
"x":[-3.2,2.1,5.3,6.5],
"y":pd.date_range("2009-01-05", periods=6, freq="M")
}
)
arr.interp(
x=np.linspace(2, 6, 10),
y=pd.date_range("2009-04-01", "2009-04-30", freq="D")
)

如果给定插值后的范围大于原有的范围(外推)的话,在原有数据范围外的数据将会赋值为 NaN

xarray1.interp_like( xarray2 )

如果已经有一个包含给定插值模板的对象,只需用interp_like即可实现插值

1
2
3
4
5
6
7
8
other = xr.DataArray(
dims=("x", "y"),
coords={
"x": np.linspace(2, 4, 10),
"y": pd.date_range("2009-04-01", "2009-04-30", freq="D")
}
)
arr.interp_like(other)

对于插值方法的选取,可以通过指定 method 方法(默认为 "linear" )来实现切换平面插值方法( "nearest" )。比如指定使用临近点插值

1
2
3
4
5
arr.interp(
x=np.linspace(2, 6, 10),
y=pd.date_range("2009-04-01", "2009-04-30", freq="D"),
method='nearest'
)

其他的插值方法参见下表所示

method插值方法一维插值二维插值
nearest临近点插值
linear线性插值
zero零阶样条插值×
slinear一阶样条插值×
quadratic二阶样条插值×
cubic三阶样条插值×

练习 - 4

通过增加步长的形式将纬度(lat)和经度(lon)的分辨率从 2.5° 增加到 1°。

1
2
3
4
5
6
7
8
ds = xr.open_dataset(".data/air_temperature.nc")
display(ds)
# 在这里写你的代码
ds.interp(
lon=np.arange(200, 331, 1),
lat=np.arange(75, 14, -1),
method="linear"
)

数据广播和对齐

维度名相同的广播

a+b自动筛选了a, b的 DataArray 中具有共同维度的共同坐标的数据进行相加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = xr.DataArray(
[[10, 20, 30, 40],
[50, 60, 70, 80],
[90, 100, 110, 120]],
dims=("x", "y"),
coords={"x": ["b", "c", "d"], "y": np.arange(1, 5)},
)
b = xr.DataArray(
[[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]],
dims=("x", "y"),
coords={"x": ["a", "b", "c"], "y": np.arange(0, 4)},
)
print(a.data)
print(b.data)
print((a + b).data)

xr.align( xarray1, xarray2, join )

等价于:对齐 → 加减

1
2
3
4
a_, b_ = xr.align(a, b, join="inner")
print(a_.data)
print(b_.data)
print((a_+b_).data)

当然若要指定不同的广播方法,可以用 xr.align 函数的 join 进行指定。

默认情况下广播的方法是取交集,即join="inner"。除此之外,join的取值还有outer, left, right, exact, override六类取值。
> inner:提取两者变量索引的交集
> outer:提取两者变量索引的并集
> left:提取仅具有左侧变量索引对应的数据
> right:提取仅具有右侧变量索引对应的数据
> exact:检验索引是否完全对齐,若左右变量的索引无法对齐,会抛出 ValueError 错误
> override:如果索引、数据的尺寸大小相同,则将右侧变量的索引重写为左侧变量的的索引

1
2
a_, b_ =xr.align(a, b, join="override")
a_.coords, b_.coords

维度名不同的广播

类似的也有如下两个数组的广播(对齐)相加

1
2
3
4
5
6
7
8
9
10
11
arr1 = xr.DataArray(
[1,2,3],
dims="x",
coords={"x": ["a", "b", "c"]},
)
arr2 = xr.DataArray(
[10,20,30,40],
dims="y",
coords={"y": np.arange(4)},
)
arr1 + arr2

xr.broadcast( xarray1, xarray2 )

等价于:广播 / 对齐 → 相加

1
2
3
4
arr1_, arr2_ = xr.broadcast(arr1, arr2) #广播/对齐
print(arr1_.data)
print(arr2_.data)
arr1_ + arr2_