<jupyter_start><jupyter_text>Álgebra Lineal con NumPy _Una vez hemos visto el manejo básico de arrays en Python con NumPy, es hora de pasar a operaciones más interesantes como son las propias del Álgebra Lineal.__Los productos escalares y las inversiones de matrices están por todas partes en los programas científicos e ingenieriles, así que vamos a estudiar cómo se realizan en Python._  Álgebra lineal Como sabemos, las operaciones del álgebra lineal aparecen con mucha frecuencia a la hora de resolver sistemas de ecuaciones en derivadas parciales y en general al linealizar problemas de todo tipo, y suele ser necesario resolver sistemas con un número enorme de ecuaciones e incógnitas. Gracias a los arrays de NumPy podemos abordar este tipo de cálculos en Python, ya que todas las funciones están escritas en C o Fortran y tenemos la opción de usar bibliotecas optimizadas al límite. El paquete de álgebra lineal en NumPy se llama `linalg`, así que importando NumPy con la convención habitual podemos acceder a él escribiendo `np.linalg`. Si imprimimos la ayuda del paquete vemos que tenemos funciones para:* Funciones básicas (norma de un vector, inversa de una matriz, determinante, traza)* Resolución de sistemas* Autovalores y autovectores* Descomposiciones matriciales (QR, SVD)* Pseudoinversas Puede que ya sepas que en la biblioteca `SciPy` se pueden encontrar también funciones de Álgebra Lineal. ¿Cuáles usar? Puedes encontrar la respuesta en este enlace: https://docs.scipy.org/doc/scipy-0.18.1/reference/tutorial/linalg.htmlscipy-linalg-vs-numpy-linalgComo de momento sólo hemos usado `NumPy` no importaremos las funciones de `SciPy`, aunque como ves, es recomendable hacerlo.<jupyter_code>import numpy as np
help(np.linalg)<jupyter_output>Help on package numpy.linalg in numpy:

NAME
    numpy.linalg

DESCRIPTION
    Core Linear Algebra Tools
    -------------------------
    Linear algebra basics:
    
    - norm            Vector or matrix norm
    - inv             Inverse of a square matrix
    - solve           Solve a linear system of equations
    - det             Determinant of a square matrix
    - lstsq           Solve linear least-squares problem
    - pinv            Pseudo-inverse (Moore-Penrose) calculated using a singular
                      value decomposition
    - matrix_power    Integer power of a square matrix
    
    Eigenvalues and decompositions:
    
    - eig             Eigenvalues and vectors of a square matrix
    - eigh            Eigenvalues and eigenvectors of a Hermitian matrix
    - eigvals         Eigenvalues of a square matrix
    - eigvalsh        Eigenvalues of a Hermitian matrix
    - qr              QR decomposition of a matrix
    - svd             Singular value decomposition [...]<jupyter_text>Recordemos que si queremos usar una función de un paquete pero no queremos escribir la "ruta" completa cada vez, podemos usar la sintaxis `from package import func`:<jupyter_code>from numpy.linalg import norm, det
norm<jupyter_output><empty_output><jupyter_text>El producto matricial usual (no el que se hace elemento a elemento, sino el del álgebra lineal) se calcula con la misma función que el producto matriz-vector y el producto escalar vector-vector: con la función `dot`, que **no** está en el paquete `linalg` sino directamente en `numpy` y no hace falta importarlo.<jupyter_code>np.dot<jupyter_output><empty_output><jupyter_text>Una consideración importante a tener en cuenta es que en NumPy no hace falta ser estricto a la hora de manejar vectores como si fueran matrices columna, siempre que la operación sea consistente. Un vector es una matriz con una sola dimensión: por eso si calculamos su traspuesta no funciona.<jupyter_code>M = np.array([
    [1, 2],
    [3, 4]
])
v = np.array([1, -1])
v.T
u = np.dot(M, v)
u<jupyter_output><empty_output><jupyter_text>Para hacer comparaciones entre arrays de punto flotante se pueden usar las funciones `np.allclose` y `np.isclose`. La primera comprueba si todos los elementos de los arrays son iguales dentro de una tolerancia, y la segunda compara elemento a elemento y devuelve un array de valores `True` y `False`.<jupyter_code>u, v
np.allclose(u, v)
np.isclose(0.0, 1e-8, atol=1e-10)<jupyter_output><empty_output><jupyter_text>__En la versión 3.5 de Python se incorporó un nuevo operador `@` para poder calcular hacer multiplicaciones de matrices de una forma más legible__<jupyter_code>u = M @ v
u
mat = np.array([[1, 5, 8, 5],
                [0, 6, 4, 2],
                [9, 3, 1, 6]])

vec1 = np.array([5, 6, 2])

vec1 @ mat<jupyter_output><empty_output><jupyter_text>Si quieres saber más, puedes leer [este artículo](http://pybonacci.org/2016/02/22/el-producto-de-matrices-y-el-nuevo-operador/) en Pybonacci escrito por _<NAME>_.  Ejercicios 1- Hallar el producto de estas dos matrices y su determinante:$$\begin{pmatrix} 1 & 0 & 0 \\ 2 & 1 & 1 \\ -1 & 0 & 1 \end{pmatrix} \begin{pmatrix} 2 & 3 & -1 \\ 0 & -2 & 1 \\ 0 & 0 & 3 \end{pmatrix}$$<jupyter_code>from numpy.linalg import det
A = np.array([
    [1, 0, 0],
    [2, 1, 1],
    [-1, 0, 1]
])
B = np.array([
    [2, 3, -1],
    [0, -2, 1],
    [0, 0, 3]
])
print(A)
print(B)
C = A @ B
C
det(C)<jupyter_output><empty_output><jupyter_text>2- Resolver el siguiente sistema:$$ \begin{pmatrix} 2 & 0 & 0 \\ -1 & 1 & 0 \\ 3 & 2 & -1 \end{pmatrix} \begin{pmatrix} 1 & 1 & 1 \\ 0 & 1 & 2 \\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} x \\ y \\ z \end{pmatrix} = \begin{pmatrix} -1 \\ 3 \\ 0 \end{pmatrix} $$<jupyter_code>M = (np.array([[2, 0, 0],
                        [-1, 1, 0],
                        [3, 2, -1]])
     @
        np.array([[1, 1, 1],
                        [0, 1, 2],
                        [0, 0, 1]]))
M
x = np.linalg.solve(M, np.array([-1, 3, 0]))
x
np.allclose(M @ x, np.array([-1, 3, 0]))<jupyter_output><empty_output><jupyter_text>3- Hallar la inversa de la matriz $H$ y comprobar que $H H^{-1} = I$ (recuerda la función `np.eye`)<jupyter_code># aeropython: preserve
A = np.arange(1, 37).reshape(6,6)
A[1, 1::2] = 0
A[3, ::2] = 1
A[4, :] += 30
B = (2 ** np.arange(36)).reshape((6,6))
H = A + B
print(H)
np.linalg.det(H)
Hinv = np.linalg.inv(H)
np.isclose(np.dot(Hinv, H), np.eye(6))
np.set_printoptions(precision=3)
print(np.dot(Hinv, H))<jupyter_output>[[ 1.125  0.25   0.5    1.     1.     4.   ]
 [-0.094  0.875 -0.25  -0.5   -0.5   -3.   ]
 [-0.125  0.25   1.     0.     4.     0.   ]
 [ 0.188  0.25   0.5    2.     1.     6.   ]
 [ 0.    -0.125  0.     0.     0.     0.   ]
 [-0.031  0.062  0.     0.     1.     1.   ]]<jupyter_text>¡No funciona! Y no solo eso sino que los resultados varían de un ordenador a otro. 4- Comprobar el número de condición de la matriz $H$.<jupyter_code>np.linalg.cond(H)<jupyter_output><empty_output><jupyter_text>La matriz está mal condicionada.  Autovalores y autovectores  La cosa no queda ahí y también se pueden resolver problemas de autovalores y autovectores:<jupyter_code>A = np.array([
    [1, 0, 0],
    [2, 1, 1],
    [-1, 0, 1]
])

np.linalg.eig(A)<jupyter_output><empty_output><jupyter_text>_Ya hemos aprendido a efectuar algunas operaciones útiles con NumPy. Estamos en condiciones de empezar a escribir programas más interesantes, pero aún queda lo mejor._* [Álgebra lineal en Python con NumPy en Pybonacci](http://pybonacci.org/2012/06/07/algebra-lineal-en-python-con-numpy-i-operaciones-basicas/) --- ¡Síguenos en Twitter! Follow @AeroPython !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');  Este notebook ha sido realizado por: <NAME>, <NAME> y <NAME>  Curso AeroPython por <NAME> y <NAME> se distribuye bajo una Licencia Creative Commons Atribución 4.0 Internacional. ---_Las siguientes celdas contienen configuración del Notebook__Para visualizar y utlizar los enlaces a Twitter el notebook debe ejecutarse como [seguro](http://ipython.org/ipython-doc/dev/notebook/security.html)_    File > Trusted Notebook<jupyter_code># Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = '../styles/aeropython.css'
HTML(open(css_file, "r").read())<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11231622077609063, 'fraction_numerical': 0.02940467582550012, 'mean_word_length': 3.333681462140992, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 54, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '258915', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 3124, 'n_tokens_neox': 2954, 'n_words': 981, 'path': 'notebooks_completos/014-NumPy-AlgebraLineal.ipynb', 'repo_name': 'rrendon502/AeroPython', 'size': '8353'}