首页 > 解决方案 > 沿特定维度从 ndarray 中减去矩阵而不重塑

问题描述

假设我有一个 2 x 2 x 100 的 ndarrayahat和一个 2 x 2 的矩阵A。从大小为 100 的维度中减去 2 x 2 矩阵而不循环或重塑的最 Pythonic 方法是什么?

for k in range(ahat.shape[2]):
    ahat[:,:,k] = ahat[:,:, k] - A

我尝试使用np.apply_over_axes但无法让它工作。更一般地说,如果我有两个兼容形状的 ndarray,就像上面的例子一样,沿着特定维度操作的首选方式是什么。例如,我可能想将每个 2x2 矩阵相乘ahatA或者我可能想np.linalg.inv沿大小为 100 的维度应用。

标签: pythonnumpy

解决方案


提升A为形状数组 (2,2,1),然后NumPy 广播将完成剩下的工作:

ahat -= A[..., None]

A[..., None]相当于A[..., np.newaxis]。它将长度为 1 的新轴添加到数组中。由于ahat具有形状 (2,2,100),并且A[..., None]具有形状 (2,2,1),NumPy 广播会将两个数组提升为兼容的形状 (2,2,100)(但以一种内存效率高的方式,实际上不会将值A从更大的数组)。

更一般地,请注意 NumPy 广播会自动将新轴添加到任何 NumPy 数组形状的左侧。因此,例如,对于任何基本的 NumPy 算术运算(如加法或乘法A),如果涉及算术运算的其他数组是 3 维的(甚至 (1 ,1,2,2) 如果另一个数组是 4 维的)。上面,我们需要A[..., None]显式添加一个新轴,因为我们希望新轴位于形状的右侧。


对于矩阵乘法,您通常会使用np.dot、 或np.einsum、 或np.tensordot。其中一些函数,例如np.einsumnp.tensordot允许您指定希望在矩阵乘法中使用的轴(因此您不需要显式添加新轴)。例如,要矩阵乘以ahatA,您可以使用

np.tensordot(ahat, A, axes=[[1], [0]])

或者

np.einsum('ijk,jl->ikl', ahat, A)

这将沿 1 轴的ahat值与沿 0 轴的值相乘A,然后求和为乘积。


推荐阅读