减去ndarray的最后一个轴

时间:2019-03-05 15:08:43

标签: python numpy indexing

  

我想用b [nn]减去a [nn,...,0]中的所有值,而   保持数组 a 的原始结构。


我从ndnumpy数组进行索引和逐元素减法时遇到问题。 就我而言,数组 a 具有6个维度

In[]: a.shape
Out[]: (101, 256, 1, 3, 1, 10)

出于一致性考虑,最小维度 N = 0 具有10个元素,最大维度 N = 5 具有101个元素。

我还有一个一维数组 b ,它的大小与最大 a 中的尺寸。

In[]: b.shape
Out[]: (101,)

我想从 a 中减去 b ,使 b 中的第 nn 个元素是 从值 a [nn,...,0] 中减去。我知道我可以使用for循环来做到这一点,但是也应该可以广播 b ,这样我可以使用类似

的东西
In[]: c= a[:,...,0]-b[somehow broadcastet or reshaped]
In[]: c.shape()
Out[]:  (101, 256, 1, 3, 1, 10)

1 个答案:

答案 0 :(得分:1)

您确实可以利用broadcasting来做到这一点。

让我们先生成一些指定形状的随机ndarrays以便检查最终尺寸是否符合预期:

a = np.random.rand(101, 256, 1, 3, 1, 10)
b = np.random.rand(101)

在这种情况下,您必须向a.ndim添加多达b个维度,以便将b中的每个值减去{{1}的最后一个维度中的每个值}}。遵循this帖子中的想法,我们可以使用np.reshape以更简洁的方式添加多达a个新尺寸,如下所示:

a.ndim

现在我们可以根据需要从b = b.reshape((-1,) + (1,)*(a.ndim-1)) print(b.shape) # (101, 1, 1, 1, 1, 1) 中减去b

a

如果我们检查a[..., 0, None] = a[..., 0, None] - b.reshape((-1,) + (1,) * (a.ndim-1)) 的形状:

a

详细信息

以下是一些有关先前答案可能引起的问题的说明。让我们考虑以下更简单的示例:

print(a.shape)
# (101, 256, 1, 3, 1, 10)

因此,在此示例中,我们可以使用与上述解决方案相同的逻辑:

a = np.array([[1,2,3],[4,5,6]])
print(a)
array([[1, 2, 3],
       [4, 5, 6]])
print(a.shape)
# (2, 3)

b = np.array([1,1])[:,None]
array([[1],
       [1]])
print(b.shape)
# (2, 1)

通过检查结果数组,如预期的那样,a[:,0,None] = a[:,0,None] - b array([[0, 2, 3], [3, 5, 6]]) 已从沿其最后一条轴的第一个索引的b中减去,因此所有行的第一列。


第一点,

  

为什么我们必须在a中添加新轴才能进行减法?

给定a的形状,有必要向a添加新轴。请注意,b是二维数组b,因此,如果直接从array([[1],[1]])中减去它,则会得到:

a

因此,这里发生的是较小的数组,即第一项,它只是a[..., 0] - b array([[0, 3], [0, 3]]) 1D中的a视图切片,已在较大的数组中广播数组,以便它们具有兼容的形状。

如果array([1, 4])的形状改为b,则不必这样做:

(2,)

但是,由于在实际解决方案中定义了b = np.array([1,1]) a[:,0] - b # array([0, 3]) 的方式,其尺寸与b相同。因此,为了获得正确的输出,我们必须向a添加一个新轴:

a

这样,我们可以获得正确的输出。


  

使用上述方法,似乎不可能将差异分配给充当a的“校正副本”的新数组?

通过查看减法的结果可以理解这个问题的答案:

a[:,0,None] - b
array([[0],
       [3]])

因此,c = a[:,0,None] - b c.shape (2, 1) 在这里是a[:,0,None]的“切片视图”。因此请注意,通过将此结果分配给a,您只保存了c的实际sliced wiew,而不是整个a。如果要在实际切片的相同位置上修改ndarray,则必须将其分配给a的相同切片视图,因此:

a

现在,由于仅修改了a[:,0,None] = a[:,0,None] - b print(a.shape) # (2, 3) 的一部分,因此结果确实具有预期的输出。如果您确实想保存原始a的副本,则可以使用np.copy,它将返回实际的副本而不是ndarray的一部分,然后将结果分配给“更正的副本”:

a