how does multiplication differ for NumPy Matrix vs Array classes?
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 dot
instead of matrixmultiply
.
E.g.
import numpy as npx = 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
.
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")>>> a1matrix([[ 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")>>> a2matrix([[ 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 * a2tTraceback (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)>>> marray([[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)>>> md1772.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)>>> marray([[ 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.Imatrix([[ 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.ITraceback (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]])