Resolver un sistema de ecuaciones algebraicas lineales con el paquete de Python scipy.linalg (no confundir con numpy.linalg)





El aparato de álgebra lineal se utiliza en varios campos: en programación lineal, econometría, en las ciencias naturales. Por separado, observo que esta rama de las matemáticas tiene demanda en el aprendizaje automático. Si, por ejemplo, necesita trabajar con matrices y vectores, entonces, muy posiblemente, en algún paso tendrá que resolver un sistema de ecuaciones algebraicas lineales (SLAE). 



SLAE es una poderosa herramienta de modelado de procesos. Si algún modelo bien estudiado basado en SLAE es adecuado para formalizar el problema, entonces será posible resolverlo con una alta probabilidad. Pero qué tan rápido depende de sus herramientas y potencia informática.



Les contaré sobre una de esas herramientas: el paquete de Python scipy.linalg de la biblioteca SciPy , que le permite resolver de manera rápida y eficiente muchos problemas utilizando el aparato del álgebra lineal.



En este tutorial, aprenderá:



  • cómo instalar scipy.linalg y preparar el tiempo de ejecución del código;
  • cómo trabajar con vectores y matrices usando NumPy;
  • por qué scipy.linalg es mejor que numpy.linalg;
  • cómo formalizar problemas usando sistemas de ecuaciones algebraicas lineales;
  • cómo resolver un SLAE usando scipy.linalg ( con un ejemplo real).


¡Si es posible, hazraCUT aquí! Es importante que la gente lea esta lista ^^ y esté interesada



Cuando se trata de matemáticas, la presentación del material debe ser coherente, de modo que una se siga de la otra. Este artículo no es una excepción: primero habrá mucha información preparatoria y solo entonces nos pondremos manos a la obra. 



Si estás listo para esto, te invito debajo del gato. Aunque, para ser honesto, se pueden omitir algunas secciones, por ejemplo, los conceptos básicos para trabajar con vectores y matrices en NumPy (si está familiarizado con él).



Instalación de scipy.linalg 



SciPy es una biblioteca Python de código abierto para computación científica: solución SLAE, optimización, integración, interpolación y procesamiento de señales. Además de linalg, contiene varios otros paquetes, por ejemplo, NumPy, Matplotlib, SymPy, IPython y pandas.



Entre otras cosas, scipy.linalg contiene funciones para trabajar con matrices: cálculo del determinante, inverso, cálculo de valores propios y vectores, y descomposición de valores singulares.



Para usar scipy.linalg, debe instalar y configurar la biblioteca SciPy. Esto se puede hacer usando la distribución de Anaconda y el sistema de administración de paquetes e instalador de Conda .



Primero, prepare el tiempo de ejecución para la biblioteca:



$ conda create --name linalg

$ conda activate linalg
      
      





Instale los paquetes necesarios:



(linalg) $ conda install scipy jupyter
      
      





Este comando puede tardar bastante. ¡No se alarme!



Sugiero usar Jupyter Notebook para ejecutar su código en un entorno interactivo. Esto no es necesario, pero para mí personalmente, facilita mi trabajo.



Antes de abrir Jupyter Notebook, debe registrar una instancia de conda linalg para usar como núcleo al crear el cuaderno. Para hacer esto, ejecute el siguiente comando:



(linalg) $ python -m ipykernel install --user --name linalg
      
      





Ahora puede abrir Jupyter Notebook:



$ jupyter notebook
      
      





Cuando esté cargado en su navegador, cree un nuevo cuaderno, haciendo clic en Nuevo linalg :







Para verificar que la instalación de la biblioteca SciPy fue exitosa, ingrese en su cuaderno:



>>>

In [1]: import scipy

      
      







NumPy para trabajar con vectores y matrices (donde sin él)



Es difícil sobreestimar el papel de los vectores y las matrices en la resolución de problemas técnicos, incluidos los problemas de aprendizaje automático.



NumPy es el paquete más popular para trabajar con matrices y vectores en Python. A menudo se usa junto con scipy.linalg. Para comenzar con matrices y vectores, debe importar el paquete NumPy:



>>>

In [2]: import numpy as np

      
      





NumPy usa un tipo especial llamado ndarray para representar matrices y vectores . Para crear un objeto ndarray, puede usar array () .



Por ejemplo, necesita crear la siguiente matriz:







Creemos una matriz como un conjunto de listas anidadas (vectores de fila):



>>>

In [3]: A = np.array([[1, 2], [3, 4], [5, 6]])

   ...: A

Out[3]:

array([[1, 2],

       [3, 4],

       [5, 6]])
      
      







Tenga en cuenta que la salida anterior ( Outp [3] ) es una representación suficientemente buena de la matriz resultante.



Y una cosa más: todos los elementos de la matriz deben y tendrán el mismo tipo. Esto se puede verificar con dtype .



>>>

In [4]: A.dtype

Out[4]:

dtype('int64')
      
      







Los elementos aquí son números enteros, por lo que su tipo genérico predeterminado es int64 . Si hubiera al menos un número de punto flotante entre ellos, todos los elementos serían float64 :



>>>

In [5]: A = np.array([[1.0, 2], [3, 4], [5, 6]])

   ...: A

Out[5]:

array([[1., 2.],

       [3., 4.],

       [5., 6.]])

In [6]: A.dtype

Out[6]:

dtype('float64')
      
      





Para mostrar la dimensión de una matriz, puede utilizar el método de forma :



>>>

In [7]: A.shape

Out[7]:

(3, 2)
      
      





Como era de esperar, la dimensión de la matriz A es 3 × 2, es decir, A tiene tres filas y dos columnas.



Cuando se trabaja con matrices, a menudo es necesario utilizar la operación de transposición, que convierte las columnas en filas y viceversa. Para transponer un vector o matriz (representado por un objeto de tipo ndarray), puede usar .transpose () o .T . Por ejemplo:



>>>

In [8]: A.T

Out[8]:

array([[1., 3., 5.],

       [2., 4., 6.]])

      
      





También puede usar .array () para crear un vector, pasando una lista de valores como argumento:



>>>

In [9]: v = np.array([1, 2, 3])

   ...: v

Out[9]:

array([1, 2, 3])

      
      





De manera similar a las matrices, usamos .shape () para mostrar la dimensión de un vector:



>>>

In [10]: v.shape

Out[10]:

(3,)
      
      





Tenga en cuenta que se parece a (3,), no a (3, 1) o (1, 3). Los desarrolladores de NumPy decidieron hacer que el mapeo de dimensiones vectoriales sea el mismo que en MATLAB. 



Para obtener la dimensión (1, 3) en la salida, sería necesario crear una matriz como esta: 



>>>

In [11]: v = np.array([[1, 2, 3]])

   ...: v.shape

Out[11]:

(1, 3)

      
      





Para (3, 1) - así:



>>>

In [12]: v = np.array([[1], [2], [3]])

   ...: v.shape

Out[12]:

(3, 1)

      
      





Como puede ver, no son idénticos.



A menudo, el problema surge de un vector de fila para hacer un vector de columna. Alternativamente, primero puede crear un vector de fila y luego usar .reshape () para convertirlo en una columna:



>>>

In [13]: v = np.array([1, 2, 3]).reshape(3, 1)

   ...: v.shape

Out[13]:

(3, 1)
      
      





En el ejemplo anterior, usamos .reshape () para obtener un vector de columna de dimensión (3, 1) a partir de un vector de dimensión (3,). Vale la pena señalar que .reshape () realiza la transformación, teniendo en cuenta que la cantidad de elementos (100% de los lugares llenos) en la matriz con la nueva dimensión debe ser igual a la cantidad de elementos en la matriz original.



En tareas prácticas, a menudo se requiere crear matrices que consistan enteramente en ceros, unos o números aleatorios. Para hacer esto, NumPy ofrece varias funciones útiles, que cubriré en la siguiente sección.



Llenado de matrices con datos



NumPy le permite crear y poblar arreglos rápidamente. Por ejemplo, para crear una matriz llena de ceros, puede usar .zeros () :



>>>

In [15]: A = np.zeros((3, 2))

   ...: A

Out[15]:

array([[0., 0.],

       [0., 0.],

       [0., 0.]])
      
      





Como argumento para .zeros (), debe especificar la dimensión de la matriz, empaquetada en una tupla (enumere los valores separados por comas y envuélvalos entre paréntesis). Los elementos de la matriz creada obtendrán el tipo float64.



Del mismo modo, puede usar .ones () para crear matrices de unos :



>>>

In [16]: A = np.ones((2, 3))

   ...: A

Out[16]:

array([[1., 1., 1.],

       [1., 1., 1.]])
      
      





Los elementos de la matriz creada también obtendrán el tipo float64. .Random.rand ()



lo ayudará a crear una matriz llena de números aleatorios :



>>>

In [17]: A = np.random.rand(3, 2)

   ...: A

Out[17]:

array([[0.8206045 , 0.54470809],

       [0.9490381 , 0.05677859],

       [0.71148476, 0.4709059 ]])
      
      





Más precisamente, el método .random.rand () devuelve una matriz con valores pseudoaleatorios (de 0 a 1) de un conjunto generado de acuerdo con la ley de distribución uniforme. Tenga en cuenta que, a diferencia de .zeros () y .ones (), .random.rand () no acepta una tupla como entrada, sino simplemente dos valores separados por comas.



Para obtener una matriz con valores pseudoaleatorios tomados de un conjunto distribuido normalmente con media cero y varianza unitaria, puede usar .random.randn () :



>>>

In [18]: A = np.random.randn(3, 2)

   ...: A

Out[18]:

array([[-1.20019512, -1.78337814],

       [-0.22135221, -0.38805899],

       [ 0.17620202, -2.05176764]])
      
      





Por que scipy.linalg es mejor que numpy.linalg



NumPy tiene un módulo numpy.linalg incorporado para resolver algunos problemas relacionados con el aparato de álgebra lineal. Scipy.linalg generalmente se recomienda por las siguientes razones:



  1. , scipy.linalg numpy.linalg, , numpy.linalg.



  2. scipy.linalg BLAS (Basic Linear Algebra Subprograms) LAPACK (Linear Algebra PACKage). . numpy.linalg BLAS LAPACK . , , scipy.linalg , numpy.linalg.


Aunque SciPy agregará dependencias a su proyecto, use scipy.linalg en lugar de numpy.linalg siempre que sea posible.



En la siguiente sección, usaremos scipy.linalg para trabajar con sistemas de ecuaciones algebraicas lineales. ¡Finalmente algo de práctica!



Formalización y resolución de problemas con scipy.linalg



Scipy.linalg puede ser una herramienta útil para resolver problemas de transporte, equilibrar ecuaciones químicas y cargas eléctricas, interpolación de polinomios, etc.



En esta sección, aprenderá a usar scipy.linalg.solve () para resolver un SLAE. Pero antes de comenzar a trabajar con el código, formalicemos el problema y luego consideremos un ejemplo simple.



Un sistema de ecuaciones algebraicas lineales es un conjunto de m ecuaciones, n variables y un vector de términos libres. El adjetivo "lineal" significa que todas las variables son de primer grado. Para simplificar, considere un SLAE, donde myn son iguales a 3:







Hay un requisito más para la “linealidad”: los coeficientes K ₁… K ₉ y el vector b ₁… b ₃ deben ser constantes (en el sentido matemático de la palabra). 



En problemas reales, los SLAE suelen contener una gran cantidad de variables, lo que imposibilita la resolución manual de los sistemas. Afortunadamente, herramientas como scipy.linalg pueden hacer el trabajo duro.



Problema 1



Primero repasaremos los conceptos básicos de scipy.linalg.solve () con un ejemplo simple, y en la siguiente sección abordaremos la tarea más difícil.



Entonces:







Pasemos a la notación matricial de nuestro sistema e introduzcamos las designaciones correspondientes: A, x y b:







Nota: el lado izquierdo en la notación del sistema original es el producto habitual de la matriz A por el vector x. 



Eso es todo, ahora puede proceder a la programación.



Escribiendo el código usando scipy.linalg.solve ()



Las entradas a scipy.linalg.solve () son la matriz A y el vector b. Deben representarse como dos matrices: A - una matriz de 2x2 yb - una matriz de 2x1. NumPy nos ayudará con esto. Por lo tanto, podemos resolver el sistema así:



>>>

1In [1]: import numpy as np

 2   ...: from scipy.linalg import solve

 3

 4In [2]: A = np.array(

 5   ...:   [

 6   ...:       [3, 2],

 7   ...:       [2, -1],

 8   ...:   ]

 9   ...: )

10

11In [3]: b = np.array([12, 1]).reshape((2, 1))

12

13In [4]: x = solve(A, b)

14   ...: x

15 Out[4]:

16 array([[2.],

17       	  [3.]])

      
      





Analicemos el código anterior:



  1. Líneas 1 y 2: importando NumPy y la función solve () de scipy.linalg.
  2. Líneas 4 a 9: Creamos la matriz de coeficientes como una matriz bidimensional llamada A.
  3. Línea 11: Cree un vector de fila b como una matriz llamada b. Para convertirlo en un vector de columna, llame a .reshape ((2, 1)).
  4. Líneas 13 y 14: llamamos .solve () en nuestro sistema, almacenamos el resultado en xy lo imprimimos. Tenga en cuenta que .solve () devuelve un vector de números de punto flotante, incluso si todos los elementos de las matrices originales son números enteros.


Si inserta x1 = 2 y x2 = 3 en las ecuaciones originales, quedará claro que esta es una solución para nuestro sistema.



A continuación, tomemos un ejemplo del mundo real más complejo.



Tarea 2: elaboración de un plan de alimentación



Esta es una de las tareas típicas que se encuentran en la práctica: encontrar las proporciones de los componentes para obtener una determinada mezcla. 



A continuación formaremos un plan de alimentación mezclando diferentes alimentos para lograr una dieta equilibrada.



Nos han dado las normas para el contenido de vitaminas en los alimentos:



  • 170 unidades de vitamina A;
  • 180 unidades de vitamina B;
  • 140 unidades de vitamina C;
  • 180 unidades de vitamina D;
  • 350 unidades de vitamina E.


La siguiente tabla muestra los resultados del análisis del producto. Un gramo de cada producto contiene una cierta cantidad de vitaminas:



Producto Vitamina A Vitamina B Vitamina C Vitamina D Vitamina e
uno uno 10 uno 2 2
2 nueve uno 0 uno uno
3 2 2 cinco uno 2
cuatro uno uno uno 2 13
cinco uno uno uno nueve 2


Es necesario combinar productos alimenticios para que su concentración sea óptima y corresponda a las normas de contenido de vitaminas en los alimentos. 



Denotemos la concentración óptima (número de unidades) para el producto 1 como x1 , para el producto 2 como x2, y así sucesivamente. Como mezclaremos productos, entonces, para cada vitamina (columna de la tabla), simplemente puede sumar los valores de todos los productos. Considerando que una dieta balanceada debe incluir 170 unidades de vitamina A, luego usando los datos de la columna "Vitamina A", compusimos la ecuación:







Se pueden elaborar ecuaciones similares para las vitaminas B, C, D, E, combinando todo en un sistema:







Escribamos el SLAE resultante en forma de matriz:







Scipy.linalg.solve () ahora se puede usar para resolver el sistema:



>>>

In [1]: import numpy as np

   ...: from scipy.linalg import solve

In [2]: A = np.array(

   ...:    [

   ...:        [1, 9, 2, 1, 1],

   ...:        [10, 1, 2, 1, 1],

   ...:        [1, 0, 5, 1, 1],

   ...:        [2, 1, 1, 2, 9],

   ...:        [2, 1, 2, 13, 2],

   ...:    ]

   ...: )

In [3]: b = np.array([170, 180, 140, 180, 350]).reshape((5, 1))

In [4]: x = solve(A, b)

   ...: x

Out[4]:

array([[10.],

       [10.],

       [20.],

       [20.],

       [10.]])
      
      





Conseguimos el resultado. Vamos a descifrarlo. Una dieta equilibrada debe incluir:



  • 10 unidades de producto 1; 
  • 10 unidades de producto 2; 
  • 20 unidades de producto 3; 
  • 20 unidades de producto 4; 
  • 10 unidades de producto 5.


¡Come bien! ¡Usa scipy.linalg y mantente saludable!








Servidores VPS en la nube con unidades NVM rápidas y pago diario. Sube tu ISO.






All Articles