在 NumPy 中方便且经济的矢量操作



有没有办法在不过度使用flatten()ravel()、创建元组以创建每个矩阵等的情况下操作 NumPy 中的矩阵?

我知道它不是 matlab,但编写 40 个字符而不是 4 个字符似乎效率不高。

例如:

A = ones(2,2) # doesn't work
A = ones((2,2)) # works with tuple
v = np.matlib.rand(2)
dot(v, A@v) # doesn't work: shapes are not aligned
vdot(v,A@v) # works 

现在我想更新矩阵列:

A[:,0]=A@v # nope! shapes are not aligned
# beautiful solution:
c = v.reshape(2,1)
c = A@c
c = c.flatten()
A[:,0]=c

我假设A的初始化是来自numpy.onesones。我们可以有一行字,就像这样——

A[:,[0]] = A@v.T

LHS :A[:,[0]]保持维数不变为2D,与A[:,0]相比,维数会减少,从而允许我们分配A@v.T,这也是2D

RHSA@v.T负责前两行代码:

c = v.reshape(2,1)
c = A@c

我们不需要c = c.flatten()的第三步,因为对于LHS,我们使用的是2D视图和前面解释的A[:,[0]]

因此,我们剩下修改后的第四步,即解决方案本身被列为本文中的第一个代码。


另一种方式

A[:,0]将是一个(2,)数组,而A@v.T将是一个(2,1)数组。因此,(A@v.T).T将是一个(1,2)阵列,可以针对A[:,0]广播。所以,这给了我们另一种方式——

A[:,0] = (A@v.T).T

ones的参数签名为:

ones(shape, dtype=None, order='C')

shape是一个论点,而不是一个开放式*args

ones(2,2)传递2作为shape2 asdtype';所以它不起作用。

ones((2,2))将元组(2,2)作为shape传递。

有时编写函数以接受元组或扩展元组,例如foo((1,2))foo(*(1,2))foo(1,2)。 但这需要在函数内部进行额外的检查。 尝试编写这样的函数来亲自查看。

此外,tuples不会增加计算成本。 Python 一直在创建和使用元组;只需在表达式中使用逗号即可创建元组(如果它不是创建列表的一部分)。

只需定义一个函数来获取参数的开放式"列表"即可创建一个元组:

def foo(*args):
print(type(args))
return args
In [634]: foo(1)
<class 'tuple'>
Out[634]: (1,)
In [635]: foo(1,2)
<class 'tuple'>
Out[635]: (1, 2)
In [636]: foo((1,2))
<class 'tuple'>
Out[636]: ((1, 2),)
In [637]: foo(*(1,2))
<class 'tuple'>
Out[637]: (1, 2)

v = np.matlib.rand(2)对我不起作用。 什么是v(形状,dtype)?matlab具有最小的二维;所以我怀疑v是 2d,甚至可能是np.matrix类数组。

vdotflattens input arguments to 1-D vectors first


好的,通过特殊导入,我得到了matlib(旧的兼容包):

In [644]: from numpy import matlib
In [645]: matlib.rand(2)
Out[645]: matrix([[ 0.32975512,  0.3491822 ]])
In [646]: _.shape
Out[646]: (1, 2)

让我们试试双点:

In [647]: v=matlib.rand(2)
In [648]: A=np.ones((2,2))
In [649]: A@v
...
ValueError: shapes (2,2) and (1,2) not aligned: 2 (dim 1) != 1 (dim 0)

为什么它对你有用?对于 2D 数组,我们可以直接使用dot.@有时充当操作员,但增加了一些自己的怪癖。

(编辑 - 稍后您使用A@c其中c是重塑的v,相当于v.T(转置)。

In [650]: np.dot(A,v.T)     # (2,2) dot (2,1) => (2,1)
Out[650]: 
matrix([[ 0.63976046],
[ 0.63976046]])
In [651]: np.dot(v,np.dot(A,v.T))    # (1,2) dot with (2,1) -> (1,1)
Out[651]: matrix([[ 0.40929344]])

想想看,由于v是np.matrix,这也有效:v * A * v.T


我们不需要使用matlib来制作随机浮点数的 2D 数组:

In [662]: v1 = np.random.rand(1,2)
In [663]: v1.shape
Out[663]: (1, 2)
In [668]: np.dot(A,v1.T)
Out[668]: 
array([[ 1.63412808],
[ 1.63412808]])
In [669]: np.dot(v1,np.dot(A,v1.T))
Out[669]: array([[ 2.67037459]])

或者如果我们跳过 2d,v11d

In [670]: v1 = np.random.rand(2)
In [671]: np.dot(A,v1)
Out[671]: array([ 0.8922862,  0.8922862])
In [672]: np.dot(v1, np.dot(A,v1))
Out[672]: 0.79617465579446423

请注意,在最后一种情况下,我们得到一个标量,而不是 (1,1) 数组(或矩阵)。

np.random.rand是那些接受*args的函数之一,扩展的"元组"。


在上一个示例中,您必须使用flat,因为A[:,0]槽是 (2,)(如果Anp.matrix它仍然是 (2,1)),而 @ 产生一个 (2,1),必须将其展平以适应 (2,)

In [675]: A@v.T
Out[675]: 
matrix([[ 0.63976046],
[ 0.63976046]])
In [676]: A[:,0].shape
Out[676]: (2,)

使用我的 1dv1A[:,0] = np.dot(A,v1)无需进一步重塑即可工作。

通常,matlibnp.matrix函数会增加混乱。 创建的目的是让任性的 MATLAB 编码人员更容易。


最简单的计算方法:

In [681]: np.einsum('i,ij,j',v1,A,v1)
Out[681]: 0.77649708535481299

但是对于(1,2)版本,我们可以做到:

In [683]: v2 = v1[None,:]
In [684]: v2
Out[684]: array([[ 0.20473681,  0.68754938]])
In [685]: v2 @ A @ v2.T
Out[685]: array([[ 0.77649709]])

最新更新