是否有办法在不过度使用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
答案 0 :(得分:2)
我假设A
的初始化与ones
的{{1}}一致。我们可以有一个单行,就像这样 -
numpy.ones
LHS: A[:,[0]] = A@v.T
将维度的数量保持为A[:,[0]]
,与2D
保持一致,A[:,0]
会减少维度,从而使我们能够分配A@v.T
,也是2D
。
RHS: A@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
答案 1 :(得分:1)
ones
的参数签名是:
ones(shape, dtype=None, order='C')
shape
是一个参数,而不是开放式*args
。
ones(2,2)
将2
传递为shape
,2 as
dtype`;所以它不起作用。
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
至少具有2维维度;所以我怀疑v
是2d,甚至可能是np.matrix
类数组。
vdot
说flattens 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
来制作随机浮点数的二维数组:
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,则v1
1d
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,)(如果A
是np.matrix
它仍然是({1}} )),而@产生一个(2,1),必须被展平以适应(2,)
In [675]: A@v.T
Out[675]:
matrix([[ 0.63976046],
[ 0.63976046]])
In [676]: A[:,0].shape
Out[676]: (2,)
使用我的1d v1
,A[:,0] = np.dot(A,v1)
无法进一步重塑。
通常,matlib
和np.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]])