NumPy Matrix与Array类的乘法有何不同?

numpy文档build议使用数组而不是matrix来处理matrix。 然而,不像八度(直到最近我还在使用),*不执行matrix乘法,您需要使用函数matrixmultipy()。 我觉得这使得代码非常不可读。

有没有人分享我的观点,并find了解决办法?

避免使用matrix类的主要原因是:a)它本质上是二维的,和b)与“正常”的numpy数组相比,有额外的开销。 如果你所做的只是线性代数,那么通过一切手段,随意使用matrix类…但我个人觉得它比它的价值更麻烦。

对于数组(在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)

就个人而言,我发现它比*操作符暗示matrix乘法更可读…

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

要了解NumPy arrays上的操作与NumPy matrix上的操作有关的关键事项是:

  • NumPymatrix是NumPy数组的一个子类

  • NumPy 数组操作是元素明智的 (一旦广播被占)

  • NumPy matrix运算遵循线性代数的一般规则

一些代码片段来说明:

 >>> 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]]) 

但是如果这两个NumPymatrix转换为数组,这个操作将失败:

 >>> 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) 

尽pipe使用NP.dot语法可以处理数组 ; 这个操作像matrix乘法一样工作:

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

所以你需要一个NumPymatrix? 即一个NumPy数组是否足以进行线性代数计算(只要您知道正确的语法,即NP.dot)?

规则似乎是,如果参数(数组)具有与给定的线性代数操作兼容的形状(mxn),那么你没事,否则,NumPy抛出。

唯一的例外我碰到(有可能是其他人) 计算matrix逆

下面是我称之为纯线性代数运算的片段(事实上,来自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 ]])) 

matrix规范

 >>>> 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.]])) 

matrix等级

 >>> 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 

matrix条件

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

尽pipe反转需要一个NumPy matrix

 >>> 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' 

但是摩尔 – 彭罗斯(Moore-Penrose)伪装似乎运作得很好

 >>> 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]]) 

在处理matrix时,点运算符会给出不同的答案。 例如,假设如下:

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

让我们把它们转换成matrix:

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

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

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

在3.5中,Python终于得到了一个matrix乘法运算符 。 语法是a @ b

参考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]]) >>> bT array([[5], [6]]) >>> A*b #not matrix multiplication! array([[ 5, 12], [15, 24]]) >>> A.dot(bT) #matrix multiplication array([[17], [39]]) >>> b = np.array([5,6]) #1D array >>> b array([5, 6]) >>> bT #not matrix transpose! array([5, 6]) >>> A.dot(b) #does not matter for multiplication array([17, 39]) 

scipy.linalg操作可以同样应用于numpy.matrix或2D numpy.ndarray对象。

这个技巧可能是你正在寻找的。 这是一种简单的操作员超载。

然后你可以像这样使用build议的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 

来自PEP 465的一个相关的引用- 如 @ petr-viktorin所提到的一个用于matrix乘法的专用中缀运算符 ,阐明了OP正在得到的问题:

numpy使用不同的__mul__方法提供了两种不同的types。 对于numpy.ndarray对象, *执行元素乘法,matrix乘法必须使用函数调用( numpy.dot )。 对于numpy.matrix对象, *执行matrix乘法,元素乘法需要函数语法。 使用numpy.ndarray编写代码工作正常。 使用numpy.matrix编写代码也能正常工作。 但是一旦我们尝试将这两段代码整合在一起, 麻烦就开始了。 需要一个ndarray并得到一个matrix代码,反之亦然,可能会崩溃或返回不正确的结果

引入@ infix操作符应该有助于统一和简化pythonmatrix代码。