xarray 在按元素和两个大小相等的数组时给出错误的结果形状

xarray gives wrong shape of result when taking elementwise and of two arrays of equal size

我有一个使用 xarray 从 NetCDF 文件加载的二维数组,我想通过将单元格值与相邻单元格值进行比较来进行某种边缘检测。我想出了这个代码:

import numpy as np
import xarray as xr

d = xr.open_dataset('https://thredds.met.no/thredds/dodsC/barents25km_files/Barents-2.5km_ZDEPTHS_his.an.2021112900.nc')

# Compare values to neighbouring cells
threshold = 0.7
mask = (d.ice_concentration[0,1:-1,1:-1] < threshold) & (d.ice_concentration[0,1:-1,:-2] > threshold)

# Check shapes
print((d.ice_concentration[0,1:-1,1:-1] < threshold).shape)
print((d.ice_concentration[0,1:-1, :-2] > threshold).shape)
print(mask.shape)

输出:

(947, 737)
(947, 737)
(947, 736)

所以我的问题是我使用 & 在两个相同形状的数组上按元素取 and,但结果具有不同的形状。我假设在幕后发生了一些与维度有关的神奇事情,这样每个单元格都会与自身进行比较,而不是与相邻的单元格进行比较。 np.sum(mask) returns 零这一事实支持了这一点。

如果我在几个地方添加 .values,我会得到正确的形状,并且会得到我期望的结果,其中 np.sum(mask) 是一个大于零的数字:

# Compare values to neighbouring cells
threshold = 0.7
mask = (d.ice_concentration[0,1:-1,1:-1].values < threshold) & (d.ice_concentration[0,1:-1,:-2].values > threshold)

# Check shapes
print((d.ice_concentration[0,1:-1,1:-1] < threshold).shape)
print((d.ice_concentration[0,1:-1, :-2] > threshold).shape)
print(mask.shape)

输出:

(947, 737)
(947, 737)
(947, 737)

这是xarray的故意行为吗?我想如果我试图比较具有相同维度的不同数组,这种行为可能是有意义的,但在这种情况下,它的意义为零(至少对我而言)。还是我做错了什么?

xarray 在执行数据操作时使用沿给定维度的标签来对齐数据。通过这种方式,它在处理未对齐坐标方面更类似于 pandas 而不是 numpy,尽管默认情况下 xarray 始终使用内部连接对齐数据:

In [1]: import xarray as xr, pandas as pd, numpy as np

In [2]: da = xr.DataArray(np.arange(5), dims=['level'], coords=[list('abcde')])

In [3]: da
Out[3]:
<xarray.DataArray (level: 5)>
array([0, 1, 2, 3, 4])
Coordinates:
  * level    (level) <U1 'a' 'b' 'c' 'd' 'e'

查看示例中的两种情况时,您正在使用偏移量对数据进行切片(slice(0, length-1)slice(1, length))。执行此操作时,请注意“级别”的索引不再对齐:

In [4]: a = da[:len(da.level)-1]
   ...: b = da[1:len(da.level)]

In [5]: a
Out[5]:
<xarray.DataArray (level: 4)>
array([0, 1, 2, 3])
Coordinates:
  * level    (level) <U1 'a' 'b' 'c' 'd'

In [6]: b
Out[6]:
<xarray.DataArray (level: 4)>
array([1, 2, 3, 4])
Coordinates:
  * level    (level) <U1 'b' 'c' 'd' 'e'

将两者相加时,或在涉及广播和自动对齐的任何操作中(请参阅下面的文档参考),将从结果中删除缺失值。此外,在结果中,请注意总和是元素总和,其中每个元素基于标签 (b + b, c + c, d + d) 对齐,而不是基于位置 (b + a, c + b , d + c).

In [7]: a + b
Out[7]:
<xarray.DataArray (level: 3)>
array([2, 4, 6])
Coordinates:
  * level    (level) <U1 'b' 'c' 'd'

你要找的是首先使用 shift 方法移动轴标签,以便坐标标签对齐 在你做加法之前 :

In [10]: c = da.shift(level=-1)

In [11]: c
Out[11]:
<xarray.DataArray (level: 5)>
array([ 1.,  2.,  3.,  4., nan])
Coordinates:
  * level    (level) <U1 'a' 'b' 'c' 'd' 'e'

In [12]: a + c
Out[12]:
<xarray.DataArray (level: 4)>
array([1., 3., 5., 7.])
Coordinates:
  * level    (level) <U1 'a' 'b' 'c' 'd'

现在,当您在 a + c 上添加时,坐标会按您喜欢的方式排列。

有关详细信息,请参阅 broadcasting by dimension name and automatic alignment 上的 xarray 计算文档。