```{python}
import numpy as np
import scipy.linalg as la
```
Algebra lineal con SciPy
La paquetería más utilizada para trabajar álgebra lineal con Python es SciPy, específicamente el paquete scipy.linalg, el cual se encuentra basado en NumPy.
Primero descargamos ambos paquetes:
Matrices con NumPy
En NumPy, las matrices son denominadas arrays. Los arrays pueden tener muchas dimensiones. Un array de dimensión 1 (1D) puede considerarse como una simple lista de números (vector), mientras que un array de 2D es una matriz. En consecuencia, un array 3D será un cubo de números. Cuando seleccionamos un renglón o una columna de una matriz (2D NumPy array), el resultado es un array de 1D llamado slice. En álgebra lineal, a esta selección le llamamos vector renglón o vector columna, según sea el caso. Es importante que nunca perdamos de vista el tamaño, la forma y el número de dimensiones de los arrays con los que nos encontremos trabajando.
Atributos de un NumPy array
Vamos a crear un array de 1D para verificar su tamaño, forma y dimensión:
```{python}
= np.array([1,3,-2,1])
a print(a)
```
[ 1 3 -2 1]
Verificamos el número de dimensiones:
```{python}
a.ndim```
1
Verificamos la forma del array:
```{python}
a.size```
4
Ahora sabemos que nuestro array es 1D, que es una tupla de extensión 1 y que tiene tamaño 4 (hay cuatro entradas dentro del array). A continuación vamos a crear un array 2D (matriz).
```{python}
= np.array([[1,2],[3,5],[4,5],[7,-8]])
b print(b)
```
[[ 1 2]
[ 3 5]
[ 4 5]
[ 7 -8]]
Verificamos el número de dimensiones:
```{python}
b.ndim```
2
Verificamos la forma (i x j):
```{python}
b.shape```
(4, 2)
Verificamos el tamaño (número de entradas en la matriz):
```{python}
b.size```
8
Podemos seleccionar un renglón o una columna de nuestro array 2D y obtendremos un array 1D. A esta técnica se le conoce como slicing:
```{python}
= b[:,0]
colb1 print(colb1)
```
[1 3 4 7]
Verificamos el número de dimensiones en el slice:
```{python}
colb1.ndim```
1
Ahora, verificamos la forma y el tamaño del slice:
```{python}
colb1.shape```
(4,)
```{python}
colb1.size```
4
Cuando seleccionamos un slice de un array 2D obtenemos un array 1D o tupla. Sin embargo, si quisieramos convertir ese arreglo en un vector columna 2D, debemos usar un método llamado reshape
.
```{python}
print(colb1)
```
[1 3 4 7]
```{python}
= np.array([colb1]).reshape(4,1)
vectorb1 print(vectorb1)
```
[[1]
[3]
[4]
[7]]
Nuevamente, verificamos el número de dimensiones, forma y tamaño de nuestro array:
```{python}
print('Dimensiones:', vectorb1.ndim)
print('Forma:', vectorb1.shape)
print('Tamaño:', vectorb1.size)
```
Dimensiones: 2
Forma: (4, 1)
Tamaño: 4
Es importante notar que las variables colb1
y vectorb1
son diferentes tipos de objeto en Python, aunque contienen los mismos datos. Mientras que el primero es una tupla 1D, el segundo es un vector columna de 2D.
```{python}
print(colb1)
print('Dimensiones:', colb1.ndim)
print('Forma:', colb1.shape)
print('Tamaño:', colb1.size)
```
[1 3 4 7]
Dimensiones: 1
Forma: (4,)
Tamaño: 4
Operaciones con matrices y funciones
Operaciones aritméticas
Las operaciones aritméticas básicas que podemos hacer en Python se pueden hacer con nuestros NumPy arrays: +
, -
, *
, /
y **
. Estas operaciones se harán para cada elemento (distinto a las operaciones con matrices). Como ejemplo, vamos a crear un array y después realizaremos una multiplicación aritmética básica de Python.
```{python}
= np.array([[3,4],[-1,5]])
c print(c)
```
[[ 3 4]
[-1 5]]
Realizamos una multiplicación simple:
```{python}
= c * c
mult print(mult)
print('Forma:', mult.shape)
```
[[ 9 16]
[ 1 25]]
Forma: (2, 2)
Con esta operación aritmética básica, Python multiplica elemento por elemento y nos regresa un array con forma (2,2). Es muy imprtante señalar que este resultado no es una multiplicación de matrices.
Multiplicación de matrices
Para realizar una multiplicación de matrices con NumPy, usaremos el operador @
. Veamos la diferencia entre la multiplicación aritmética básica en Python y la multiplicación de matrices en NumPy.
```{python}
= c @ c
matrixmult print(matrixmult)
```
[[ 5 32]
[-8 21]]
Hagamos la siguiente operación con matrices:
\(2I + 3A - AB\) para:
\[ A = \begin{pmatrix} 1 & 3\\ -1 & 7 \end{pmatrix} ; \, B = \begin{pmatrix} 5 & 2\\ 1 & 2 \end{pmatrix} \]
donde I es la matriz identidad de tamaño 2.
Primero creamos nuestras matrices o arrays con NumPy.
```{python}
= np.array([[1,3],[-1,7]])
A print(A)
```
[[ 1 3]
[-1 7]]
```{python}
= np.array([[5,2],[1,2]])
B print(B)
```
[[5 2]
[1 2]]
```{python}
= np.eye(2)
I print(I)
```
[[1. 0.]
[0. 1.]]
```{python}
2*I + 3*A - A @ B
```
array([[-3., 1.],
[-5., 11.]])
Potencia de matrices
No existe un símbolo específico para realizar la operación de potencia de matrices, por lo que debemos exportar la función matrix_power
del subpaquete de NumPy numpy.linalg
.
```{python}
from numpy.linalg import matrix_power as mpow
```
Primero creamos nuestro array.
```{python}
= np.array([[3,4],[-1,5]])
M print(M)
```
[[ 3 4]
[-1 5]]
Ahora elevaremos la matriz M
a la potencia 5.
```{python}
5)
mpow(M,```
array([[-1525, 3236],
[ -809, 93]])
Comparemos este resultado con el resultado de multiplicar la matriz M
cinco veces por sí misma.
```{python}
@ M @ M @ M @ M
M ```
array([[-1525, 3236],
[ -809, 93]])
Matriz Transpuesta
Podemos obtener la matriz transpuesta usando el atributo .T
. Nuevamente usaremos nuestra matriz M
.
```{python}
print(M)
```
[[ 3 4]
[-1 5]]
```{python}
print(M.T)
```
[[ 3 -1]
[ 4 5]]
Matriz Inversa
Podemos encontrar la inversa de una matriz usando la función scipy.linalg.inv
.
```{python}
= np.array([[1,2],[3,4]])
A print(A)
```
[[1 2]
[3 4]]
```{python}
la.inv(A)```
array([[-2. , 1. ],
[ 1.5, -0.5]])
Determinante de una matriz
Encontramos el determinante de una matriz con la función scipy.linalg.det
.
```{python}
= np.array([[1,2],[3,4]])
A print(A)
```
[[1 2]
[3 4]]
```{python}
la.det(A)```
-2.0