¿En qué se diferencia la multiplicación para Matrix vs Matrix?

Los documentos numpy recomiendan el uso de matrices en lugar de matrices para trabajar con matrices. Sin embargo, a diferencia de la octava (que estaba usando hasta hace poco), * no realiza la multiplicación de matrices, debe usar la función matrixmultipy (). Siento que esto hace que el código sea muy ilegible.

¿Alguien comparte mis opiniones y ha encontrado una solución?

La razón principal para evitar el uso de la clase de matrix es que a) es inherentemente bidimensional, yb) hay una sobrecarga adicional en comparación con una matriz numpy “normal”. Si todo lo que estás haciendo es álgebra lineal, entonces, por todos los medios, siéntete libre de usar la clase matricial … Personalmente, me parece más problemático de lo que vale.

Para las matrices (antes de Python 3.5), use el dot lugar de la matrixmultiply de forma matrixmultiply .

P.ej

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

O en las versiones más nuevas de numpy, simplemente use x.dot(y)

Personalmente, lo encuentro mucho más legible que el operador * que implica la multiplicación de matrices …

Para matrices en Python 3.5, use x @ y .

Las cosas clave que se deben conocer para las operaciones en matrices NumPy frente a las operaciones en matrices NumPy son:

  • La matriz NumPy es una subclase de la matriz NumPy

  • Las operaciones de matriz NumPy son elementales (una vez que se contabiliza la difusión)

  • Las operaciones de matriz NumPy siguen las reglas ordinarias del álgebra lineal

algunos fragmentos de código para ilustrar:

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

pero estas operaciones fallan si estas dos matrices NumPy se convierten en matrices:

 >>> a1 = NP.array(a1) >>> a2t = NP.array(a2t) >>> a1 * a2t Traceback (most recent call last): File "", line 1, in  a1 * a2t ValueError: operands could not be broadcast together with shapes (4,3) (3,4) 

aunque el uso de la syntax NP.dot funciona con arrays ; Estas operaciones funcionan como multiplicación de matrices:

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

¿Alguna vez necesitas una matriz NumPy? es decir, ¿será suficiente una matriz NumPy para el cálculo del álgebra lineal (siempre que conozca la syntax correcta, es decir, NP.dot)?

la regla parece ser que si los argumentos (matrices) tienen formas (mxn) compatibles con una operación de álgebra lineal dada, entonces está bien, de lo contrario, NumPy lanza.

La única excepción que he encontrado (probablemente hay otras) es calcular la matriz inversa .

a continuación hay fragmentos en los que he llamado una operación de álgebra lineal pura (de hecho, del módulo de Álgebra Lineal de Numpy) y se pasa en una matriz NumPy

determinante de una matriz:

 >>> 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)  >>> md = LA.det(m) >>> md 1772.9999999999995 

vectores propios / pares de valores propios :

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

norma matricial

 >>>> LA.norm(m) 22.0227 

factorización 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.]])) 

rango de matriz

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

condición de la matriz:

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

la inversión requiere una matriz NumPy aunque:

 >>> a1 = NP.matrix(a1) >>> type(a1)  >>> 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 "", line 1, in  a1.I AttributeError: 'numpy.ndarray' object has no attribute 'I' 

pero el pseudoinverso de Moore-Penrose parece funcionar bien

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

En 3.5, Python finalmente consiguió un operador de multiplicación de matrices . La syntax es a @ b .

Hay una situación en la que el operador de puntos dará respuestas diferentes cuando se trata de matrices y de matrices. Por ejemplo, supongamos lo siguiente:

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

Vamos a convertirlos en matrices:

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

Ahora, podemos ver una salida diferente para los dos casos:

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

Referencia de http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html

…, se desaconseja el uso de la clase numpy.matrix , ya que no agrega nada que no se pueda lograr con los objetos 2D numpy.ndarray , y puede llevar a una confusión sobre qué clase se está utilizando. Por ejemplo,

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

Las operaciones de scipy.linalg pueden aplicarse igualmente a numpy.matrix o a objetos 2D numpy.ndarray .

Este truco puede ser lo que buscas. Es una especie de simple sobrecarga del operador.

Luego puedes usar algo como la clase de Infix sugerida como esta:

 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 

Una cita pertinente de PEP 465 – Un operador de infijo dedicado para la multiplicación de matrices , como lo menciona @ petr-viktorin, aclara el problema al que se estaba enfrentando el OP:

[…] numpy proporciona dos tipos diferentes con diferentes métodos __mul__ . Para los objetos numpy.ndarray , * realiza la multiplicación elementwise, y la multiplicación matricial debe usar una llamada de función ( numpy.dot ). Para los objetos numpy.matrix , * realiza la multiplicación de matrices, y la multiplicación de elementwise requiere la syntax de la función. Escribir código usando numpy.ndarray funciona bien. Escribir código usando numpy.matrix también funciona bien. Pero el problema comienza tan pronto como tratamos de integrar estas dos piezas de código juntas. El código que espera un ndarray y obtiene una matrix , o viceversa, puede fallar o devolver resultados incorrectos

La introducción del operador @ infix debería ayudar a unificar y simplificar el código de matriz de Python.

La función matmul (desde numpy 1.10.1) funciona bien para ambos tipos y devuelve el resultado como una clase de matriz 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)) 

Salida:

 (matrix([[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]]), ) (array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]), ) (matrix([[ 6, 6, 6, 6], [15, 15, 15, 15], [24, 24, 24, 24], [33, 33, 33, 33]]), ) 

Como Python 3.5, como se mencionó anteriormente , también puede usar un nuevo operador de multiplicación de matrices @ como

 C = A @ B 

y obtener el mismo resultado que el anterior.