【问题标题】:Subtract over last axis of ndarray减去 ndarray 的最后一个轴
【发布时间】:2019-03-05 15:08:43
【问题描述】:

我想将 a[nn,...,0] 中的所有值减去 b[nn] 而 保持数组的原始结构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)

【问题讨论】:

    标签: python numpy indexing


    【解决方案1】:

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

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

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

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

    b = b.reshape((-1,) + (1,)*(a.ndim-1))
    print(b.shape)
    # (101, 1, 1, 1, 1, 1)
    

    现在我们可以根据需要从a 中减去b

    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 中添加一个新轴进行减法?

    鉴于b 的形状,有必要向a 添加一个新轴。注意b 是一个二维数组array([[1],[1]]),所以如果你直接从a 中减去它,你会得到:

    a[..., 0] - b
    array([[0, 3],
           [0, 3]])
    

    所以,这里发生的是较小的数组,即第一项,它只是来自aarray([1, 4])1D 视图切片,已在较大的数组中广播,以便它们兼容形状。

    如果b 的形状改为(2,),则不需要这样做:

    b = np.array([1,1])
    a[:,0] - b
    # array([0, 3])
    

    但是由于实际解决方案中b的定义方式,它与a具有相同的维度。所以为了得到正确的输出,我们必须给a添加一个新轴:

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

    这样我们就得到了正确的输出。


    使用上面的方法,似乎无法将差异分配给充当 a 的“更正副本”的新数组?

    看一下减法的结果就可以理解这个问题的答案:

    c = a[:,0,None] - b
    c.shape
    (2, 1)
    

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

    a[:,0,None] = a[:,0,None] - b
    print(a.shape)
    # (2, 3)
    

    现在结果确实有预期的输出,因为我们只修改了a 的一部分。如果您确实想保存原始ndarray 的副本,您可以使用np.copy,它将返回实际副本而不是a 的一部分,然后将结果分配给“更正后的副本”:

    a_c = np.copy(a)
    a_c[:,0,None] = a[:,0,None] - b
    

    【讨论】:

    • 好的,我知道了。非常感谢您的宝贵时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-25
    相关资源
    最近更新 更多