## 问题：NumPy矩阵与数组类的乘法有何不同？

numpy文档建议使用数组而不是矩阵来处理矩阵。但是，与八度（我直到最近才使用）不同，*不执行矩阵乘法，您需要使用函数matrixmultipy（）。我觉得这使代码非常不可读。

The numpy docs recommend using array instead of matrix for working with matrices. However, unlike octave (which I was using till recently), * doesn’t perform matrix multiplication, you need to use the function matrixmultipy(). I feel this makes the code very unreadable.

Does anybody share my views, and has found a solution?

## 回答 0

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

print np.dot(x,y)``````

The main reason to avoid using the `matrix` class is that a) it’s inherently 2-dimensional, and b) there’s additional overhead compared to a “normal” numpy array. If all you’re doing is linear algebra, then by all means, feel free to use the matrix class… Personally I find it more trouble than it’s worth, though.

For arrays (prior to Python 3.5), use instead of `matrixmultiply`.

E.g.

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

print np.dot(x,y)
``````

Or in newer versions of numpy, simply use `x.dot(y)`

Personally, I find it much more readable than the `*` operator implying matrix multiplication…

For arrays in Python 3.5, use `x @ y`.

## 回答 1

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

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

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

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

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

the key things to know for operations on NumPy arrays versus operations on NumPy matrices are:

• NumPy matrix is a subclass of NumPy array

• NumPy array operations are element-wise (once broadcasting is accounted for)

• NumPy matrix operations follow the ordinary rules of linear algebra

some code snippets to illustrate:

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

but this operations fails if these two NumPy matrices are converted to arrays:

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

though using the NP.dot syntax works with arrays; this operations works like matrix multiplication:

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

so do you ever need a NumPy matrix? ie, will a NumPy array suffice for linear algebra computation (provided you know the correct syntax, ie, NP.dot)?

the rule seems to be that if the arguments (arrays) have shapes (m x n) compatible with the a given linear algebra operation, then you are ok, otherwise, NumPy throws.

the only exception i have come across (there are likely others) is calculating matrix inverse.

below are snippets in which i have called a pure linear algebra operation (in fact, from Numpy’s Linear Algebra module) and passed in a NumPy array

determinant of an array:

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

eigenvectors/eigenvalue pairs:

``````>>> 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 norm:

``````>>>> LA.norm(m)
22.0227
``````

qr factorization:

``````>>> 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 rank:

``````>>> 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 condition:

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

inversion requires a NumPy matrix though:

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

but the Moore-Penrose pseudoinverse seems to works just fine

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

## 回答 2

In 3.5, Python finally got a matrix multiplication operator. The syntax is `a @ b`.

## 回答 3

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

There is a situation where the dot operator will give different answers when dealing with arrays as with dealing with matrices. For example, suppose the following:

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

Lets convert them into matrices:

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

Now, we can see a different output for the two cases:

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

## 回答 4

…，使用的numpy.matrix气馁，因为它增加了什么，无法与2D来完成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])``````

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

…, the use of the numpy.matrix class is discouraged, since it adds nothing that cannot be accomplished with 2D numpy.ndarray objects, and may lead to a confusion of which class is being used. For example,

``````>>> 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 operations can be applied equally to numpy.matrix or to 2D numpy.ndarray objects.

## 回答 5

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

This trick could be what you are looking for. It is a kind of simple operator overload.

You can then use something like the suggested Infix class like this:

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

## 回答 6

numpy提供了两种使用不同`__mul__`方法的不同类型。对于`numpy.ndarray`对象，`*`执行元素乘法，矩阵乘法必须使用函数调用（`numpy.dot`）。对于`numpy.matrix`对象，`*`执行矩阵乘法，而元素乘法则需要函数语法。使用编写代码`numpy.ndarray`效果很好。使用编写代码`numpy.matrix`也可以。但是，一旦我们尝试将这两段代码集成在一起，麻烦就会开始。预期为`ndarray`并得到`matrix`或相反的代码可能会崩溃或返回错误的结果

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

A pertinent quote from PEP 465 – A dedicated infix operator for matrix multiplication , as mentioned by @petr-viktorin, clarifies the problem the OP was getting at:

[…] numpy provides two different types with different `__mul__` methods. For `numpy.ndarray` objects, `*` performs elementwise multiplication, and matrix multiplication must use a function call (`numpy.dot`). For `numpy.matrix` objects, `*` performs matrix multiplication, and elementwise multiplication requires function syntax. Writing code using `numpy.ndarray` works fine. Writing code using `numpy.matrix` also works fine. But trouble begins as soon as we try to integrate these two pieces of code together. Code that expects an `ndarray` and gets a `matrix`, or vice-versa, may crash or return incorrect results

The introduction of the `@` infix operator should help to unify and simplify python matrix code.

## 回答 7

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

``C = A @ B``

Function matmul (since numpy 1.10.1) works fine for both types and return result as a numpy matrix class:

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

Output:

``````(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'>)
``````

Since python 3.5 as mentioned early you also can use a new matrix multiplication operator `@` like

``````C = A @ B
``````

and get the same result as above.