【问题标题】:Broadcast an operation along specific axis in python在python中沿特定轴广播操作
【发布时间】:2017-01-14 15:20:47
【问题描述】:

在 python 中,假设我有一个正方形 numpy 矩阵 X,大​​小为 nxn,我有一个 numpy 向量 a大小 n

很简单,我想执行 X - a 的广播减法,但我希望能够指定沿哪个维度,以便我可以指定减法是沿轴0 或轴 1。

如何指定轴?

【问题讨论】:

  • 您保持aaxis=1 相同。为axis=0 添加一个带有a[:,None] 的新轴。这一切都是为了沿着那个轴推动元素。

标签: python arrays numpy matrix array-broadcasting


【解决方案1】:

从两个不同的维度开始(至少在标签中)

  • X形状(n,m)
  • a形状(n,)
  • b形状(m,)

将这些结合起来的方法是:

(n,m)-(n,) => (n,m)-(n,1) => (n,m)
X - a[:,None]     

(n,m)-(m,) => (n,m)-(1,m) => (n,m)
X - b[None,:]
X - b      # [None,:] is automatic, if needed.

基本点是,当数字维度不同时,numpy 可以在开头添加新维度,但您必须在末尾明确添加新维度。

或者将 2 个一维数组组合成一个外积(差异):

(n,) - (m,) => (n,1)-(1,m) => (n,m)
a[:,None] - b[None,:]
a[:,None] - b

如果没有这些规则,a-b 可能会导致 (n,m)(m,n) 或其他内容。

并且有 2 个匹配长度的数组:

(n,) - (n,) => (n,)
a - a

(n,) - (n,) => (n,1)-(1,n) => (n,n)
a[:,None]-a[None,:]

=============

要编写一个接受axis 参数的函数,您可以使用np.expand_dims

In [220]: np.expand_dims([1,2,3],0)
Out[220]: array([[1, 2, 3]])    # like [None,:]
In [221]: np.expand_dims([1,2,3],1)
Out[221]:             # like [:,None]
array([[1],
       [2],
       [3]])

def foo(X, a, axis=0):
    return X - np.expand_dims(a, axis=axis)

用作:

In [223]: foo(np.eye(3),[1,2,3],axis=0)
Out[223]: 
array([[ 0., -2., -3.],
       [-1., -1., -3.],
       [-1., -2., -2.]])
In [224]: foo(np.eye(3),[1,2,3],axis=1)
Out[224]: 
array([[ 0., -1., -1.],
       [-2., -1., -2.],
       [-3., -3., -2.]])

【讨论】:

    【解决方案2】:

    让我们用随机元素生成数组

    输入:

    In [62]: X
    Out[62]: 
    array([[ 0.32322974,  0.50491961,  0.40854442,  0.36908488],
           [ 0.58840196,  0.1696713 ,  0.75428203,  0.01445901],
           [ 0.27728281,  0.33722084,  0.64187916,  0.51361972],
           [ 0.39151808,  0.6883594 ,  0.93848072,  0.48946276]])
    
    In [63]: a
    Out[63]: array([ 0.01278876,  0.01854458,  0.16953393,  0.37159562])
    

    我。沿axis=1减法

    让我们沿着axis=1做减法,即我们想从X的第一行,X的第二行中减去a等等。为了便于检查正确性,我们只使用X 的第一行:

    In [64]: X[0] - a
    Out[64]: array([ 0.31044099,  0.48637503,  0.23901049, -0.00251074])
    

    深入那里,那里发生了什么:

    X[0,0] - a[0], X[0,1] - a[1], X[0,2] - a[2] , X[0,3] - a[3]
    

    所以,我们将X 的第二个轴与a 的第一个轴匹配。因为,X2Da1D,两者已经对齐:

    X :  n x n
    a :      n
    

    所以,我们只需执行X-a 即可获得所有减法:

    In [65]: X-a
    Out[65]: 
    array([[ 0.31044099,  0.48637503,  0.23901049, -0.00251074],
           [ 0.5756132 ,  0.15112672,  0.5847481 , -0.3571366 ],
           [ 0.26449405,  0.31867625,  0.47234523,  0.1420241 ],
           [ 0.37872932,  0.66981482,  0.76894679,  0.11786714]])
    

    还有,最后看看我们之前获得的X[0] - a是不是在这里。

    重要提示:这里要注意的是a elems 将沿着一个轴,并且沿着该减法将进行并且广播将沿着另一轴发生。因此,在这种情况下,即使在 axis=1 上发生减法,a 的元素也会沿 axis=0 广播。

    二。沿axis=0减法

    同样,让我们​​沿着axis=0 做减法,即我们想从X 的第一列、X 的第二列中减去a,以此类推。为了便于检查正确性,我们只使用X 的第一列:

    In [67]: X[:,0]-a
    Out[67]: array([ 0.31044099,  0.56985738,  0.10774888,  0.01992247])
    

    深入那里,那里发生了什么:

    X[0,0] - a[0], X[1,0] - a[1], X[2,0] - a[2] , X[3,0] - a[3]
    

    因此,我们将X 的第一个轴与a 的第一个轴匹配。因为X2Da1D,所以我们需要将a 扩展到2D 并使用a[:,None] 保持所有元素沿其第一个轴:

    X          :  n x n
    a[:,None]  :  n x 1
    

    所以,我们使用X-a[:,None] 来获得所有减法:

    In [68]: X-a[:,None]
    Out[68]: 
    array([[ 0.31044099,  0.49213085,  0.39575566,  0.35629612],
           [ 0.56985738,  0.15112672,  0.73573745, -0.00408557],
           [ 0.10774888,  0.16768691,  0.47234523,  0.34408579],
           [ 0.01992247,  0.31676379,  0.5668851 ,  0.11786714]])
    

    还有,最后看看我们之前得到的X[:,0] - a是不是在这里。

    【讨论】:

    • 这种方式的问题是,当X轴数一开始未知的情况下,效果并不好。另外,如果 X 有 7 个维度,那么写 X-a[:,None,None,None,None,None,None] 看起来就非常错误。
    • 您也可以使用np.newaxis 代替None,以提高可读性。
    • @Hyperplane 要添加n 维度,您可以使用a[(..., *([None] * n))]。解释这里发生了什么:用于索引的元组;省略号... 用于扩展所有现有维度;将[None] 乘以n 乘以None 得到一个列表;使用前导 * 解压缩 Nones 的列表。顺便提一句。我更喜欢np.newaxis 而不是None
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多