python - tutorial - ¿Cómo difiere la multiplicación para las clases NumPy Matrix vs Array?
numpy tutorial español pdf (7)
Los documentos numpy recomiendan usar matriz en lugar de matriz para trabajar con matrices. Sin embargo, a diferencia de la octava (que estaba usando hasta hace poco), * no realiza la multiplicación de matrices, necesita usar la función matrixmultipy (). Siento que esto hace que el código sea muy ilegible.
¿Alguien comparte mis puntos de vista y ha encontrado una solución?
En 3.5, Python finalmente obtuvo un operador de multiplicación de matrices . La sintaxis es a @ b
.
Hay una situación en la que el operador de puntos dará respuestas diferentes cuando se trate de arreglos como cuando se trata con 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 un resultado diferente para los dos casos:
>>> print numpy.dot(a.T, b)
14
>>> print am.T*bm
[[1. 2. 3.]
[2. 4. 6.]
[3. 6. 9.]]
La razón principal para evitar el uso de la clase de matrix
es que a) es intrínsecamente 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 no dudes en usar la clase de matriz ... Personalmente, creo que es más problemático de lo que vale.
Para arreglos (antes de Python 3.5), use dot
lugar de 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 versiones más nuevas de numpy, simplemente use x.dot(y)
Personalmente, me parece mucho más legible que el operador *
lo que implica la multiplicación de la matriz ...
Para arreglos en Python 3.5, use x @ y
.
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 numpy.ndarray 2D, 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]])
>>> 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])
Las operaciones de scipy.linalg se pueden aplicar igualmente a numpy.matrix oa objetos numpy.ndarray 2D.
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 que estaba teniendo el OP:
[...] numpy proporciona dos tipos diferentes con diferentes métodos
__mul__
. Para los objetosnumpy.ndarray
,*
realiza la multiplicación por elementos, y la multiplicación de matrices debe usar una llamada a la función (numpy.dot
). Para objetosnumpy.matrix
,*
realiza la multiplicación de matrices, y la multiplicación de elementos requiere la sintaxis de la función. Escribir código usandonumpy.ndarray
funciona bien. Escribir código usandonumpy.matrix
también funciona bien. Pero los problemas comienzan tan pronto como intentamos integrar estos dos códigos juntos. Código que espera unndarray
y obtiene unamatrix
, o viceversa, puede bloquearse o devolver resultados incorrectos
La introducción del operador @
infix debería ayudar a unificar y simplificar el código matricial de python.
las cosas clave que debe saber para las operaciones en matrices NumPy frente a las operaciones en matrices NumPy son:
La matriz NumPy es una subclase de matriz NumPy
Las operaciones de la matriz NumPy son basadas en los elementos (una vez que se contabiliza la transmisió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 esta operación falla 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 "<pyshell#277>", line 1, in <module>
a1 * a2t
ValueError: operands could not be broadcast together with shapes (4,3) (3,4)
aunque el uso de la sintaxis NP.dot funciona con matrices ; esta operación funciona como la multiplicación de la matriz:
>> NP.dot(a1, a2t)
array([[127, 84, 85, 89],
[218, 139, 142, 173],
[226, 157, 136, 103],
[352, 197, 214, 393]])
Entonces, ¿alguna vez necesitas una matriz NumPy? es decir, ¿será suficiente una matriz NumPy para el cálculo de álgebra lineal (siempre que conozca la sintaxis correcta, es decir, NP.dot)?
la regla parece ser que si los argumentos (matrices) tienen formas (mxn) compatibles con la operación de álgebra lineal dada, entonces estás bien; de lo contrario, arroja NumPy.
la única excepción que he encontrado (hay otras) es calcular la matriz inversa .
a continuación hay fragmentos en los que he llamado operación de álgebra lineal pura (de hecho, desde el módulo de álgebra lineal de Numpy) y pasé 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)
<type ''numpy.ndarray''>
>>> md = LA.det(m)
>>> md
1772.9999999999995
pares eigenvectores / eigenvalue :
>>> 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
qr factorización :
>>> 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 la 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:
>>> 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''
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]])
Este truco podría ser lo que estás buscando. Es una especie de sobrecarga de operador simple.
A continuación, puede utilizar algo así como la clase Infix sugerida de esta manera:
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