NumPy 中方便且经济的向量操作
Convenient and economic vector manipulation in 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.ones
中的 ones
。我们可以有一个单线,就像这样 -
A[:,[0]] = A@v.T
LHS : 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
,我们正在使用带有 A[:,[0]]
的 2D
视图,如前所述。
因此,我们只剩下经过修改的第四步,即解决方案本身列为此 post 中的第一个代码。
另一种方式
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
作为 shape
传递,并且 2 as
dtype`;所以它不起作用。
ones((2,2))
将元组 (2,2)
作为 shape
传递。
有时函数被编写为接受元组或扩展元组,例如foo((1,2))
、foo(*(1,2))
、foo(1,2)
。但这需要在函数内部进行额外检查。自己写个这样的函数试试看吧
另外tuples
不增加计算成本。 Python 一直在创建和使用元组;只需在表达式中使用逗号即可创建元组(如果它不是制作列表的一部分)。
简单地定义一个函数来接受一个开放式 'list' 参数创建一个元组:
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
是二维的,甚至可能是 np.matrix
class 数组。
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)
为什么它对你有用?对于二维数组,我们可以直接使用 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
的函数,扩展的 'tuple'.
在你的最后一个例子中你必须使用 flat
因为 A[:,0]
插槽是 (2,) (如果 A
是 np.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,)
使用我的 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]])
有没有一种方法可以在不过度使用 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.ones
中的 ones
。我们可以有一个单线,就像这样 -
A[:,[0]] = A@v.T
LHS : 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
,我们正在使用带有 A[:,[0]]
的 2D
视图,如前所述。
因此,我们只剩下经过修改的第四步,即解决方案本身列为此 post 中的第一个代码。
另一种方式
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
作为 shape
传递,并且 2 as
dtype`;所以它不起作用。
ones((2,2))
将元组 (2,2)
作为 shape
传递。
有时函数被编写为接受元组或扩展元组,例如foo((1,2))
、foo(*(1,2))
、foo(1,2)
。但这需要在函数内部进行额外检查。自己写个这样的函数试试看吧
另外tuples
不增加计算成本。 Python 一直在创建和使用元组;只需在表达式中使用逗号即可创建元组(如果它不是制作列表的一部分)。
简单地定义一个函数来接受一个开放式 'list' 参数创建一个元组:
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
是二维的,甚至可能是 np.matrix
class 数组。
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)
为什么它对你有用?对于二维数组,我们可以直接使用 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
的函数,扩展的 'tuple'.
在你的最后一个例子中你必须使用 flat
因为 A[:,0]
插槽是 (2,) (如果 A
是 np.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,)
使用我的 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]])