我想取一个时间维度为1的xarray数据集,只需复制数据即可将时间维度从1增加到N。最有效的方法是什么?我已经尝试了几种方法,比如expand_dims和stack,但似乎都不能达到我想要的效果。
最终我希望能够moc10_H11-moc_ctrl_clim其中结果将具有与moc10_H11(35(相同的维度。现在,当我这样做的时候,输出的时间维度只有1。
为了清晰起见,moc_ctrl_clim:
Dimensions:
time: 1, lat_aux_grid: 395, moc_z: 61
Coordinates: time (time) object 0001-01-01 00:00:00
lat_aux_grid (lat_aux_grid) float32 -79.49 -78.95 -78.42 ... 89.47 90.0
moc_z (moc_z) float32 0.0 1e+03 ... 5.25e+05 5.5e+05
Data variables:
MOC (time, moc_z, lat_aux_grid) float64
dask.array<chunksize=(1, 61, 395), meta=np.ndarray>
moc10_H11具有:
Dimensions:
time: 35, lat_aux_grid: 395, moc_z: 61
Coordinates: time (time) object 0001-01-01 00:00:00
lat_aux_grid (lat_aux_grid) float32 -79.49 -78.95 -78.42 ... 89.47 90.0
moc_z (moc_z) float32 0.0 1e+03 ... 5.25e+05 5.5e+05
Data variables:
MOC (time, moc_z, lat_aux_grid) float64
dask.array<chunksize=(1, 61, 395), meta=np.ndarray>
简短的回答,压缩数据,使xarray的自动对齐规则生效:
da = da.squeeze(dim='time', drop=True)
现在,您可以与一个按时间索引的数组配对,数据将自动广播。
解释
这背后的原因在于numpy的基于形状的广播和xarray的基于维度名称的广播之间的差异。
按形状排列的麻木广播
来自numpy文档:
当对两个数组进行操作时,NumPy会按元素比较它们的形状。它从尾部(即最右侧(尺寸开始,然后向左移动。时两个维度兼容
- 它们是相等的,或者
- 其中一个是1
例如,如果第一个维度对齐,则可以在列向量和数组之间执行元素相加:
In [3]: col_vector = np.ones(shape=(3, 1))
In [4]: col_vector
Out[4]:
array([[1.],
[1.],
[1.]])
In [5]: array = np.arange(12).reshape(3, 4)
In [6]: array
Out[6]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [7]: col_vector + array
Out[7]:
array([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.]])
当col_vector
被添加到array
时,numpy识别出col_vector
沿着轴1具有长度1,并且array
具有长度4,因此col_vector
在被添加之前应该沿着轴1被广播(平铺(为具有长度4。
按维度名称进行xarray广播
从xarray文档计算:
DataArray
对象会根据维度名称而不是轴顺序自动对齐(用numpy的说法是"广播"(。使用xarray,您不需要转置数组或插入长度为1的维度来进行数组操作,就像通常在numpy中使用numpy.reshape()
或numpy.newaxis
所做的那样。
除此之外,在xarray文档中自动对齐:
Xarray强制二进制操作中使用的对象的索引坐标(即与维度同名的坐标,用*标记(之间的对齐。[…]如果任一参数中缺少维度的坐标值,则所有匹配的维度都必须具有相同的大小。
适应上面的例子不仅需要分配名称和坐标维度,而且还需要从列向量中删除第二个维度:
In [2]: vector = xr.DataArray(np.ones(shape=3), dims=['x'], coords=[[0, 1, 2]])
In [3]: vector
Out[3]:
<xarray.DataArray (x: 3)>
array([1., 1., 1.])
Coordinates:
* x (x) int64 0 1 2
In [4]: arr = xr.DataArray(
...: np.arange(12).reshape(3, 4),
...: dims=['x', 'time'],
...: coords=[[0, 1, 2], pd.date_range('2020-01-01', periods=4, freq='D')],
...: )
In [5]: arr
Out[5]:
<xarray.DataArray (x: 3, time: 4)>
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Coordinates:
* x (x) int64 0 1 2
* time (time) datetime64[ns] 2020-01-01 2020-01-02 2020-01-03 2020-01-04
In [6]: vector + arr
Out[6]:
<xarray.DataArray (x: 3, time: 4)>
array([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.]])
Coordinates:
* x (x) int64 0 1 2
* time (time) datetime64[ns] 2020-01-01 2020-01-02 2020-01-03 2020-01-04
广播长度-1维度到更长维度
在您的问题中,您有一个沿时间维度长度为1的数组,您希望对另一个具有较长时间坐标的数组进行广播。这在上面的例子中相当于具有一个";矢量";时间维度中的长度为1:
In [7]: vector = xr.DataArray(
...: np.ones(shape=(3, 1)),
...: dims=['x', 'time'],
...: coords=[[0, 1, 2], pd.date_range('2020-01-01', periods=1, freq='D')],
...: )
当针对具有长度为4的时间维度的arr
广播此消息时,仅保留交集:
In [8]: vector + arr
Out[8]:
<xarray.DataArray (x: 3, time: 1)>
array([[1.],
[5.],
[9.]])
Coordinates:
* time (time) datetime64[ns] 2020-01-01
* x (x) int64 0 1 2
通过首先用da.squeeze
:压缩和丢弃时间调光,可以实时广播数据
In [9]: vector.squeeze('time', drop=True) + arr
Out[9]:
<xarray.DataArray (x: 3, time: 4)>
array([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.]])
Coordinates:
* x (x) int64 0 1 2
* time (time) datetime64[ns] 2020-01-01 2020-01-02 2020-01-03 2020-01-04
请注意,此方法忽略time
坐标中第一个数组中的信息,而假设该信息适用于第二个数组中time
的所有元素。如果这就是你想要的,那么挤压&如图所示,下降是可行的。