how does multiplication differ for NumPy Matrix vs Array classes? how does multiplication differ for NumPy Matrix vs Array classes? python python

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