在python中沿特定轴广播操作

在python中沿特定轴广播操作,python,arrays,numpy,matrix,array-broadcasting,Python,Arrays,Numpy,Matrix,Array Broadcasting,在python中,假设我有一个大小为nxn的正方形numpy矩阵X,我有一个大小为n的numpy向量a 非常简单,我想执行X-a的广播减法,但我想能够指定沿哪个维度,以便可以指定减法沿轴0或轴1 如何指定轴?让我们用随机元素生成数组 投入: In [62]: X Out[62]: array([[ 0.32322974, 0.50491961, 0.40854442, 0.36908488], [ 0.58840196, 0.1696713 , 0.75428203,

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

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


如何指定轴?

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

投入:

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])
I.沿
轴的减法=1

让我们沿着
axis=1
进行减法,也就是说,我们要从
X
的第一行、第二行
X
中减去
a
,依此类推。为了便于检查正确性,我们只使用
X
的第一行:

In [64]: X[0] - a
Out[64]: array([ 0.31044099,  0.48637503,  0.23901049, -0.00251074])
In [67]: X[:,0]-a
Out[67]: array([ 0.31044099,  0.56985738,  0.10774888,  0.01992247])
深入到那里,那里发生的是:

X[0,0] - a[0], X[0,1] - a[1], X[0,2] - a[2] , X[0,3] - a[3]
X[0,0] - a[0], X[1,0] - a[1], X[2,0] - a[2] , X[3,0] - a[3]
因此,我们将
X
的第二个轴与
a
的第一个轴进行匹配。由于,
X
2D
a
1D
,两者都已对齐:

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]])
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
在这里

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

II。沿
轴的减法=0

类似地,让我们沿着
轴=0
进行减法,即,我们要从
X
的第一列、第二列
X
中减去
a
,依此类推。为了便于检查正确性,我们只使用
X
的第一列:

In [64]: X[0] - a
Out[64]: array([ 0.31044099,  0.48637503,  0.23901049, -0.00251074])
In [67]: X[:,0]-a
Out[67]: array([ 0.31044099,  0.56985738,  0.10774888,  0.01992247])
深入到那里,那里发生的是:

X[0,0] - a[0], X[0,1] - a[1], X[0,2] - a[2] , X[0,3] - a[3]
X[0,0] - a[0], X[1,0] - a[1], X[2,0] - a[2] , X[3,0] - a[3]
因此,我们将
X
的第一个轴与
a
的第一个轴进行匹配。由于,
X
2D
a
1D
,我们需要将
a
扩展到
2D
,并使用
a[:,None]
保持所有元素沿其第一轴:

X          :  n x n
a[:,None]  :  n x 1
因此,我们使用
X-a[:,None]
来获得所有减法:

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]])
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]-前面获得的
在这里。

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

  • X
    shape
    (n,m)
  • a
    shape
    (n,)
  • b
    shape
    (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个1d阵列组合到一个外部产品中(区别):

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

并具有2个匹配长度数组:

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

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

要编写一个采用
参数的函数,可以使用
np.expand\u 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.]])

您保持
a
axis=1
相同。为
axis=0
添加带有
a[:,无]
的新轴。这一切都是关于沿着这个轴推动元素。这种方法的问题是,当X轴的数量在开始时未知时,它并不真正起作用。另外,如果X有7个维度,那么写
X-a[:,无,无,无,无,无]
看起来非常错误。此外,您可以使用
np.newaxis
而不是
None
,以提高可读性。@Hyperplane要添加
n
维度,可以使用
a[(…,*([None]*n])
。来解释这里发生了什么:用于索引的元组;省略号
用于扩展所有现有维度;将
[None]
乘以
n
None
;用前导的
*
解包
None
s列表。顺便说一句,我更喜欢
np.newaxis
而不是
None