NumPy 矩阵和 Array 类的乘法有什么不同?

在处理矩阵时,numpy 文档推荐使用数组而不是矩阵。但是,与 octave (我最近一直在使用)不同,* 不执行矩阵乘法,需要使用函数 Matrix/multipy ()。我觉得这使得代码非常不可读。

有人赞同我的观点,并找到了解决办法吗?

247153 次浏览

避免使用 matrix类的主要原因是: a)它本身是二维的,b)与“普通”数组相比有额外的开销。如果你所做的一切都是线性代数,那么无论如何,请随意使用矩阵类... 个人认为它更多的麻烦比它的价值,虽然。

对于数组(在 Python 3.5之前) ,使用 dot而不是 matrixmultiply

例如。

import numpy as np
x = np.arange(9).reshape((3,3))
y = np.arange(3)


print np.dot(x,y)

或者在 numpy 的新版本中,只需使用 x.dot(y)

就我个人而言,我发现它比意味着矩阵乘法的 *操作员更具可读性... ..。

对于 Python 3.5中的数组,使用 x @ y

对于 笨蛋 数组和 NumPy 矩阵的操作,需要知道的关键事项是:

  • NumPy 矩阵是 NumPy 数组的 子类

  • NumPy 数组操作是 元素方面(一旦广播被计算在内)

  • NumPy 矩阵操作遵循线性代数的一般规则

一些代码片段来说明:

>>> from numpy import linalg as LA
>>> import numpy as NP


>>> a1 = NP.matrix("4 3 5; 6 7 8; 1 3 13; 7 21 9")
>>> a1
matrix([[ 4,  3,  5],
[ 6,  7,  8],
[ 1,  3, 13],
[ 7, 21,  9]])


>>> a2 = NP.matrix("7 8 15; 5 3 11; 7 4 9; 6 15 4")
>>> a2
matrix([[ 7,  8, 15],
[ 5,  3, 11],
[ 7,  4,  9],
[ 6, 15,  4]])


>>> a1.shape
(4, 3)


>>> a2.shape
(4, 3)


>>> a2t = a2.T
>>> a2t.shape
(3, 4)


>>> a1 * a2t         # same as NP.dot(a1, a2t)
matrix([[127,  84,  85,  89],
[218, 139, 142, 173],
[226, 157, 136, 103],
[352, 197, 214, 393]])

但是如果这两个 NumPy 矩阵被转换成数组,这个操作就会失败:

>>> a1 = NP.array(a1)
>>> a2t = NP.array(a2t)


>>> a1 * a2t
Traceback (most recent call last):
File "<pyshell#277>", line 1, in <module>
a1 * a2t
ValueError: operands could not be broadcast together with shapes (4,3) (3,4)

虽然使用 < em > NP.dot 语法可以与 数组一起工作,但是这种操作的工作方式类似于矩阵乘法:

>> NP.dot(a1, a2t)
array([[127,  84,  85,  89],
[218, 139, 142, 173],
[226, 157, 136, 103],
[352, 197, 214, 393]])

你需要一个 NumPy 矩阵吗?例如,NumPy 数组是否足以进行线性代数计算(如果您知道正确的语法,例如 NP.dot) ?

规则似乎是,如果参数(数组)的形状(m x n)与给定的线性代数操作兼容,那么就可以了,否则,NumPy 抛出。

我遇到的唯一例外(可能还有其他例外)是 计算矩阵的逆矩阵

下面是我调用纯线性代数运算(事实上,来自 NumPy 的线性代数模块)并在 NumPy 数组中传递的片段

数组的行列式:

>>> m = NP.random.randint(0, 10, 16).reshape(4, 4)
>>> m
array([[6, 2, 5, 2],
[8, 5, 1, 6],
[5, 9, 7, 5],
[0, 5, 6, 7]])


>>> type(m)
<type 'numpy.ndarray'>


>>> md = LA.det(m)
>>> md
1772.9999999999995

特征向量/特征值 对:

>>> LA.eig(m)
(array([ 19.703+0.j   ,   0.097+4.198j,   0.097-4.198j,   5.103+0.j   ]),
array([[-0.374+0.j   , -0.091+0.278j, -0.091-0.278j, -0.574+0.j   ],
[-0.446+0.j   ,  0.671+0.j   ,  0.671+0.j   , -0.084+0.j   ],
[-0.654+0.j   , -0.239-0.476j, -0.239+0.476j, -0.181+0.j   ],
[-0.484+0.j   , -0.387+0.178j, -0.387-0.178j,  0.794+0.j   ]]))

矩阵 范围:

>>>> LA.norm(m)
22.0227

Qr 分解 :

>>> LA.qr(a1)
(array([[ 0.5,  0.5,  0.5],
[ 0.5,  0.5, -0.5],
[ 0.5, -0.5,  0.5],
[ 0.5, -0.5, -0.5]]),
array([[ 6.,  6.,  6.],
[ 0.,  0.,  0.],
[ 0.,  0.,  0.]]))

矩阵 军衔:

>>> m = NP.random.rand(40).reshape(8, 5)
>>> m
array([[ 0.545,  0.459,  0.601,  0.34 ,  0.778],
[ 0.799,  0.047,  0.699,  0.907,  0.381],
[ 0.004,  0.136,  0.819,  0.647,  0.892],
[ 0.062,  0.389,  0.183,  0.289,  0.809],
[ 0.539,  0.213,  0.805,  0.61 ,  0.677],
[ 0.269,  0.071,  0.377,  0.25 ,  0.692],
[ 0.274,  0.206,  0.655,  0.062,  0.229],
[ 0.397,  0.115,  0.083,  0.19 ,  0.701]])
>>> LA.matrix_rank(m)
5

矩阵 环境监察及审核:

>>> a1 = NP.random.randint(1, 10, 12).reshape(4, 3)
>>> LA.cond(a1)
5.7093446189400954

倒置 需要一个 NumPy 矩阵:

>>> a1 = NP.matrix(a1)
>>> type(a1)
<class 'numpy.matrixlib.defmatrix.matrix'>


>>> a1.I
matrix([[ 0.028,  0.028,  0.028,  0.028],
[ 0.028,  0.028,  0.028,  0.028],
[ 0.028,  0.028,  0.028,  0.028]])
>>> a1 = NP.array(a1)
>>> a1.I


Traceback (most recent call last):
File "<pyshell#230>", line 1, in <module>
a1.I
AttributeError: 'numpy.ndarray' object has no attribute 'I'

但是 摩尔-彭罗斯伪逆看起来运行得很好

>>> LA.pinv(m)
matrix([[ 0.314,  0.407, -1.008, -0.553,  0.131,  0.373,  0.217,  0.785],
[ 1.393,  0.084, -0.605,  1.777, -0.054, -1.658,  0.069, -1.203],
[-0.042, -0.355,  0.494, -0.729,  0.292,  0.252,  1.079, -0.432],
[-0.18 ,  1.068,  0.396,  0.895, -0.003, -0.896, -1.115, -0.666],
[-0.224, -0.479,  0.303, -0.079, -0.066,  0.872, -0.175,  0.901]])


>>> m = NP.array(m)


>>> LA.pinv(m)
array([[ 0.314,  0.407, -1.008, -0.553,  0.131,  0.373,  0.217,  0.785],
[ 1.393,  0.084, -0.605,  1.777, -0.054, -1.658,  0.069, -1.203],
[-0.042, -0.355,  0.494, -0.729,  0.292,  0.252,  1.079, -0.432],
[-0.18 ,  1.068,  0.396,  0.895, -0.003, -0.896, -1.115, -0.666],
[-0.224, -0.479,  0.303, -0.079, -0.066,  0.872, -0.175,  0.901]])

这个技巧 可能就是你要找的,它是一种简单的运算符重载。

然后您可以像下面这样使用建议的 Infix 类:

a = np.random.rand(3,4)
b = np.random.rand(4,3)
x = Infix(lambda x,y: np.dot(x,y))
c = a |x| b

有一种情况,点运算符在处理数组时会给出与处理矩阵时不同的答案。例如,假设如下:

>>> a=numpy.array([1, 2, 3])
>>> b=numpy.array([1, 2, 3])

让我们把它们转换成矩阵:

>>> am=numpy.mat(a)
>>> bm=numpy.mat(b)

现在,我们可以看到这两种情况的不同输出:

>>> print numpy.dot(a.T, b)
14
>>> print am.T*bm
[[1.  2.  3.]
[2.  4.  6.]
[3.  6.  9.]]

来自 http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html的参考文献

... ,使用的 Numpy.Matrix类是 气馁,因为它没有增加什么不能完成的二维 Numpy Ndarray对象,并可能导致一个 混乱的类正在使用。比如说,

>>> import numpy as np
>>> from scipy import linalg
>>> A = np.array([[1,2],[3,4]])
>>> A
array([[1, 2],
[3, 4]])
>>> linalg.inv(A)
array([[-2. ,  1. ],
[ 1.5, -0.5]])
>>> b = np.array([[5,6]]) #2D array
>>> b
array([[5, 6]])
>>> b.T
array([[5],
[6]])
>>> A*b #not matrix multiplication!
array([[ 5, 12],
[15, 24]])
>>> A.dot(b.T) #matrix multiplication
array([[17],
[39]])
>>> b = np.array([5,6]) #1D array
>>> b
array([5, 6])
>>> b.T  #not matrix transpose!
array([5, 6])
>>> A.dot(b)  #does not matter for multiplication
array([17, 39])

Linalg 操作可以同样应用于 Numpy.Matrix或2D Numpy Ndarray对象。

在3.5中,Python 最后是 找了个矩阵乘法,语法是 a @ b

正如@petr-viktorin 提到的,来自 PEP 465-一个专用于矩阵乘法的中缀操作器的一段相关引文澄清了 OP 所面临的问题:

Numpy 提供了两种不同类型的 __mul__方法。对于 numpy.ndarray对象,*执行元素乘法,而矩阵乘法必须使用函数调用(numpy.dot)。对于 numpy.matrix对象,*执行矩阵乘法,而且元素乘需要函数语法。使用 numpy.ndarray编写代码效果很好。使用 numpy.matrix编写代码也可以很好地工作。只要我们尝试将这两段代码集成在一起,就可以使用 numpy.ndarray0。期望获得 ndarray并获得 matrix的代码,或者反过来,可能会崩溃或返回不正确的结果

@中缀操作符的引入应该有助于统一和简化 python 矩阵代码。

函数 Matmul(自从 numpy 1.10.1以来)对这两种类型都适用,返回的结果是一个 numpy 矩阵类:

import numpy as np


A = np.mat('1 2 3; 4 5 6; 7 8 9; 10 11 12')
B = np.array(np.mat('1 1 1 1; 1 1 1 1; 1 1 1 1'))
print (A, type(A))
print (B, type(B))


C = np.matmul(A, B)
print (C, type(C))

产出:

(matrix([[ 1,  2,  3],
[ 4,  5,  6],
[ 7,  8,  9],
[10, 11, 12]]), <class 'numpy.matrixlib.defmatrix.matrix'>)
(array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]), <type 'numpy.ndarray'>)
(matrix([[ 6,  6,  6,  6],
[15, 15, 15, 15],
[24, 24, 24, 24],
[33, 33, 33, 33]]), <class 'numpy.matrixlib.defmatrix.matrix'>)

因为 python 3.5就像 之前提到过一样,你也可以使用一个新的矩阵乘法操作符,比如

C = A @ B

并得到与上述相同的结果。