Python NumPy矩阵和数组类的乘法有何不同?

Python NumPy矩阵和数组类的乘法有何不同?,python,arrays,numpy,matrix,matrix-multiplication,Python,Arrays,Numpy,Matrix,Matrix Multiplication,numpy文档建议使用数组而不是矩阵来处理矩阵。但是,与octave(直到最近我才使用)不同,*不执行矩阵乘法,您需要使用函数matrixmultipy()。我觉得这使得代码很难阅读 有人同意我的观点并找到了解决方案吗?避免使用矩阵类的主要原因是a)它本质上是二维的,b)与“普通”numpy数组相比有额外的开销。如果你所做的只是线性代数,那么无论如何,请随意使用矩阵类。。。但就我个人而言,我觉得这比它的价值更麻烦 对于数组(在Python 3.5之前),使用而不是matrixmultiply 例

numpy文档建议使用数组而不是矩阵来处理矩阵。但是,与octave(直到最近我才使用)不同,*不执行矩阵乘法,您需要使用函数matrixmultipy()。我觉得这使得代码很难阅读


有人同意我的观点并找到了解决方案吗?

避免使用
矩阵
类的主要原因是a)它本质上是二维的,b)与“普通”numpy数组相比有额外的开销。如果你所做的只是线性代数,那么无论如何,请随意使用矩阵类。。。但就我个人而言,我觉得这比它的价值更麻烦

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

例如

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

就我个人而言,我发现它比暗示矩阵乘法的
*
运算符可读性好得多


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

NumPy数组上的操作与在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) 
那么你需要一个NumPy矩阵吗?一个NumPy数组是否足以用于线性代数计算(前提是您知道正确的语法,即NP.dot)

规则似乎是,若参数(数组)的形状(mxn)和给定的线性代数运算兼容,那个么您就可以了,否则,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.norm(m)
22.0227
>>> 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
qr因式分解

>>>> LA.norm(m)
22.0227
>>> 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
矩阵

>>>> LA.norm(m)
22.0227
>>> 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
矩阵条件

>>>> LA.norm(m)
22.0227
>>> 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矩阵,但:

可能就是你要找的。它是一种简单的运算符重载

然后,您可以使用建议的中缀类,如下所示:

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.]]
参考自

…,不鼓励使用numpy.matrix类,因为它添加了2Dnumpy.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])
scipy.linalg操作可以同样应用于numpy.matrix或2Dnumpy.ndarray对象。

在3.5版中,Python最后一款。语法是
a@b

正如@petr viktorin所提到的,一段相关的引语澄清了OP的问题:

[…]numpy提供了两种不同类型的
\uuuuu mul\uuuuu
方法。对于
numpy.ndarray
对象,
*
执行元素乘法,矩阵乘法必须使用函数调用(
numpy.dot
)。对于
numpy.matrix
对象,
*
执行矩阵乘法,元素乘法需要函数语法。使用
numpy.ndarray
编写代码效果很好。使用
numpy.matrix
编写代码也可以但一旦我们尝试将这两段代码集成在一起,麻烦就开始了。需要ndarray并获取矩阵的代码,或者反之亦然,可能会崩溃或返回不正确的结果

@
中缀运算符的引入应有助于统一和简化python矩阵代码

函数(因为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'>)

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

您是在征求意见,而不是问题。我们是否有更具体的方法可以帮助您或指导您使其更具可读性?实际上,如果您学习线性代数,文档建议使用矩阵,而不想使用乘法(),那么问题出在哪里?我没有详细阅读文档。只是好奇,数组比矩阵类有什么优势?我发现数组不区分行和列。是因为数组被认为是张量而不是矩阵吗?正如Joe指出的,矩阵类是2维的这一事实是非常有限的。这种设计背后的想法是什么,比如,为什么不使用一个单独的matlab/octave这样的矩阵类呢?我想主要的问题是python没有
*
vs'*'语法用于元素级vs矩阵乘法。如果有,那就更简单了,尽管我很惊讶他们选择
*
来表示元素乘法而不是矩阵乘法。当你有一堆乘法时,它是不可读的,例如x'a'*Ax。@elexhobby-
x.T.dot(a.T)。dot(a)。dot(x)
对每个人来说都是不可读的,I.m.o。如果你主要是做矩阵乘法,那么无论如何,使用
numpy.matrix
!顺便问一下,为什么矩阵乘法叫做“点”?在什么意义上它是点积?@amcnabb-矩阵乘法有时在教科书(在那些书中)中被称为“点积”