Didáctica y Software

Ejemplos básicos de álgebra lineal con python

Byron Jiménez Oviedo
Universidad Nacional Costa Rica, Costa Rica
Katalina Oviedo Rodríguez
Universidad Técnica Nacional, Costa Rica
Universidad Nacional Costa Rica, Costa Rica

Ejemplos básicos de álgebra lineal con python

Revista Digital: Matemática, Educación e Internet, vol. 21, núm. 1, pp. 1-15, 2020

Instituto Tecnológico de Costa Rica

Derechos Reservados © 2020 Revista digital Matemática, Educación e Internet

Recepción: 30 Septiembre 2019

Aprobación: 15 Marzo 2020

Resumen: En muchas ocasiones, durante el desarrollo de un curso, es realmente difícil (por la premura de abarcar los contenidos) dar ejemplos concretos y aplicaciones de la teoría que se ha desarrollado. Este material ofrece una presentación de algunas aplicaciones o visualizaciones que se pueden desarrollar con los contenidos vistos en curso de álgebra lineal básica, pasando por operaciones matriciales, transformaciones y vectores propios. Para el desarrollo de estos temas se utilizará el lenguaje de programación python. Por lo cual se recomienda un conocimiento básico en programación o en python.

Palabras clave: Álgebra lineal, aplicaciones, transformaciones en imágenes, descomposición en valores singulares.

Abstract: Many times during the development of a course it is really difficult (due to the rush to cover the contents) to give specific examples and applications of the theory that has been developed. This material offers a presentation of some applications or visualizations that can be developed with the contents in the basic course of linear algebra, going through matrix operations, transformations and eigenvalues and eigenvectors. The python programming language will be used to develop these topics. Therefore, basic knowledge in programming or python is recommended.

Keywords: Linear algebra, applications, transformations in images, singular values decomposition.

1.1 Introducción

Es claro que los cursos de matemática a nivel universitario se vuelven muy teóricos y usualmente están alejados de aplicaciones concretas. Un curso de álgebra lineal básica (donde se estudia: matrices y sistemas de ecuaciones lineales, espacios vectoriales, transformaciones lineales y valores y vectores propios) no se escapa de esto último, y a pesar de tener aplicaciones intrínsecas teórias, es natural que el estudiante se pregunte por la utilidad práctica.

Este artículo pretende dar ejemplos concretos donde el álgebra lineal es el eje primordial y su desarrollo es pragmático y simple. En esta primera parte hemos seleccionado dos ejemplos que son muy visuales, es decir, el lector además de darse cuenta de la aplicación como tal, también va a poder visualizarla. La primera de dichas aplicaciones está relacionada con transformaciones afines: rotación, traslación, multiplicación por escalar, entre otras. Estas transformaciones se van a aplicar a dos tipos de objetos. El primero será una imagen vectorial, es decir, una imagen digital conformada por segmentos, polígonos, arcos y otras. El segundo objeto es una imagen digital basada en pixeles. El tratamiento de ambas tienen ciertas disimilitudes que son interesantes de tratar [1, 4, 3].

La segunda aplicación está relacionada con una descomposición de matrices y con valores y vectores propios. Específicamente, vamos a tratar la factorización matricial SVD (descomposición en valores singulares [2, 5, 6, 7]), la cual tiene muchas aplicaciones tales como: el cálculo de pseudoinversas, ajuste de mínimo cuadrados, y aproximación de matrices, entre otras [2, 7]. En especial, vamos a utilizar esta descomposición para la compresión de imágenes. Ya que, como veremos una imagen es una matriz donde cada posición contiene el “color” del pixel en dicha posición. En el caso, de que el rango de la matriz es significativamente pequeño que sus dimensiones el método nos ayudará a poder generar una imagen similar (matriz aproximada) pero con la característica que se necesita menos información que la original.

Toda esta manipulación vamos a tratarla con el lenguaje de programación python. Además del propósito de exponer nuestros ejemplos, usar este lenguaje ayudará también a una introducir o mejorar las habilidades y competencias con dicho lenguaje de programación.

1.2 Visualización de operaciones matriciales

Recordemos que una transformación lineal T del espacio vectorial V al espacio vectorial W es una regla que asigna a cada vector v ∈ V un único vector T(v) en W, tal que

T(u + v) = T(u) +T(v), para todo u, v ∈ V.

T(c · u) = c · T(u), para todo u ∈ V, c ∈ ℝ.

En esta sección queremos visualizar cómo un espacio se transforma al aplicar una transformación lineal. De hecho, vamos a trabajar con transformaciones T : ℝm→ℝn, específicamente cuando n=m=2.

Ahora, utilizando la propiedades de las matrices no es difícil mostrar que para una matriz A de tamaño m × n la aplicación T(X) = AX con X ∈ ℝm. es una transformación lineal. Existen un conjunto de transformaciones lineales que son parte de este tipo de transformaciones, llamadas transformaciones afines. Estas transformaciones preservan puntos, rectas, rectas paralelas, entre otras. Todo esto puede ser visualizado al transformar (rotar, trasladar, escalar, etc.) objetos en 2D o 3D.

Algunas de estas transformaciones en 2D no corresponden a una multiplicación directa de matrices 2×2, sino que debemos introducir una nueva representación para poder utilizar matrices 3×3, a esto se le llama coordenadas homogéneas. Por ejemplo, un punto (x, y) ∈ ℝ2 puede ser identificado con el punto (x, y, 1) ∈ ℝ3, así el punto (x, y, 1) es la coordenada homogénea de (x, y). En general, para un vector v ∈ ℝn la forma homogénea de v es v ^ = (v, 1) ∈ ℝn+1.

Algunas de estas transformaciones afines en ℝ3 se presentan en el cuadro 1.2, donde el efecto de la transformación en un punto X = (x, y, z)T es determinado al multiplicar la matriz A por X, dando un nuevo punto que vamos a representar por X’ = (x', y', z')T.

Transformaciones
Cuadro 1.2
Transformaciones

Transformaciones
Cuadro 1.2 (cont.)
Transformaciones

En cada transformación, dada en la cuadro 1.2, se puede observar que la variable z no es modificada. Por ejemplo, la rotación que se presenta es una rotación alrededor del eje z. Ahora, vamos a aprovechar que un punto en ℝ2 se puede representar en python como una tripleta (x, y, b) donde x, y representan las coordenadas del punto y b es un índice o bandera de cada punto. Como para efectos de este ejemplo no vamos a necesitar dicho índice vamos a considerarlo convenientemente como 1, es decir, cada punto (x, y) en el plano lo vamos a representar en python con (x, y, 1) (lo tomamos como su coordenada homogénea).

Vamos a dibujar una figura simple la cual puede ser fácilmente representada con una matriz y con la cual vamos a poder visualizar el efecto de cada transformación.

Letra E
Figura 1.1
Letra E

En la Figura 1.1 vemos dibujado la letra E. Podemos representar esta figura matricialmente al guardar coordenadas estratégicas, en este caso los puntos esquinas tal y como se ponen en envidencia en la Figura 1.1. La matriz que representa esta letra es E ∈ ℝ12X3 definida por

E = 0 0 1 3 0 1 3 1 1 1 1 1 1 2 1 2 2 1 2 3 1 1 3 1 1 4 1 3 4 1 3 5 1 0 5 1

Cada fila de la matriz anterior representa una coordenada homogénea de un punto en ℝ2, así que si en ese orden unimos cada punto por medio de un segmento de recta vamos a obtener el dibujo deseado. Por ejemplo, si queremos reflejar la Figura 1.1 con respecto al eje y debemos realizar la multiplicación de la matriz E y la matriz de reflexión correspondiente, es decir,

E · - 1 0 0 0 1 0 0 0 1 = 0 0 1 3 0 1 3 1 1 1 1 1 1 2 1 2 2 1 2 3 1 1 3 1 1 4 1 3 4 1 3 5 1 0 5 1 - 1 0 0 0 1 0 0 0 1 = 0 0 1 - 3 0 1 - 3 1 1 - 1 1 1 - 1 2 1 - 2 2 1 - 2 3 1 - 1 3 1 - 1 4 1 - 3 4 1 - 3 5 1 0 5 1

De lo anterior obtenemos la letra E de la Figura 1,1 reflejada con respeto al eje x (vea la Figura 1.2).

Reflexión de la letra E
Figura 1.2
Reflexión de la letra E

Para realizar todo esto en python vamos a trabajar con el paquete NumPy, el cual es una biblioteca que proporciona una gran cantidad de operaciones sobre arreglos multidimensionales. Además, también vamos a trabajar con la biblioteca matplotlib la cual nos ayudará a la hora de graficar datos en listas. Para llamar a estas bibliotecas debemos escribir


Para poder definir la matriz que contiene las coordenadas de la figura que queremos dibujar utilizamos el siguiente código (una vez importadas las las bibliotecas)


El resto del código (con comentarios en verde) corresponde a la definición de las matrices que determinan la transformación, el uso de dichas transformaciones y la gráfica correspondiente.



En la Figura 1.3 se presenta algunas transformaciones ya ejecutadas (para la rotación se ha usado θ = π 3 y θ = 3 π 2 ).

Transformaciones afines
Figura 1.3
Transformaciones afines

1.3 Transformaciones en imágenes

Con la información que tenemos podemos realizar transformaciones directamente a imágenes digitales. Recordemos que todo esto está ya estudiado y que lo que pretendemos es dar ejemplos de aplicaciones del álgebra lineal. Es claro que el lector a partir de esto podrá investigar las formas más óptimas tanto a nivel teórico como a nivel de programación de cómo realizar los ejemplos que aquí se brindan.

Es probable que el lector esté familiarizado con la palabra pixel (picture element), la cual definimos como el elemento gráfico más pequeño de una imagen, que puede tomar solo un color a la vez.

Formato RGB
Figura 14
Formato RGB

En otras palabras, el pixel es un cuadro pequeño que contiene un color y que forma parte de una imagen. Al número de pixeles de una imagen se le llama resolución (el tamaño físico depende de la resolución que se tome). Ahora, una imagen a color puede ser interpretada como como una matriz 3D de tamaño px × py × 3, cada entrada se puede referenciar por medio de (i, j, k) donde i ∈ {0, 1, 2, · · · , px}, j ∈ {0, 1, 2, · · · , py} y k ∈ {0, 1, 2}. Cada matriz va a representar un color en el modelo de color RGB, esto es un acrónimo de Red, Green, Blue (existen otros tipos de modelos de color tales como: CMYK, HSL y HSV). La intensidad de cada color va de 0 a 255 (ver Figura 1.4 ).

La imagen a color es una combinación de las tres matrices, por ejemplo, la imagen dada en la Figura 1.5 de tamaño p. × p. = 2448 × 3264 pixels es la combinación de las imágenes en la Figura 1.4.

Imagen de tamaño 2448 x 3264
Figura 1.5
Imagen de tamaño 2448 x 3264

Vamos a utilizar de nuevo las bibliotecas numpy y matplotlib. En python podemos cargar una imagen en la matriz “img” con el comando “img=plt.imread(path)”, donde “path” es la ubicación de la imagen. Ahora, para acceder a la información de la intensidad de los colores escribiendo “img[i,j]”, por ejemplo, para i = j = 1 obtenemos “array([108, 147, 214], dtype=uint8)”. Esto quiere decir que la intesidad del rojo (R) es 108, la de verde (G) es 147 y la de azul (B) 214. En el caso que se quiere acceder a un color en particular, digamos verde, basta escribir “img[i,j,1]”.



La estrategia a seguir para la transformación de una imagen es la siguiente:

  1. 1. Vamos a crear una nueva imagen en negro img N.
  2. 2. Luego iteramos sobre cada pixel de la imagen original img.
  3. 3. Trasformamos las coordenadas de i j y obtenemos las nuevas coordenadas i ' j ' .
  4. 4. Si i ' j ' no son coordenadas enteras tomamos la parte entera y obtenemos i j .
  5. 5. Colocamos lo información en i j de la imagen original en la coordenada i j .i.e.,

    i m g N i j = i m g i j

Ahora, recuerde que las entradas de una imagen están conformadas por números enteros. Sin embargo, algunas de las transformaciones pueden generar índices no enteros. Si tomamos la decisión de redondear o utilizar la función parte entera traerá problemas pues puede generar pixeles sin información nueva y por lo tanto quedarán en negro (color asignado por defecto a la imagen nueva). Existen también otras situaciones que podrían generar este mismo problema aún cuando las coordenadas transformadas sean enteras. Por ejemplo, si hace un cambio de escala al doble. Es claro que todas los índices generados son enteros, sin embargo, solo se colocará información en las coordenadas de la forma 2i 2j y las coordenadas de la forma 2i+1 2j+1 quedarán con la infomarción antigua. Observe que este tipo de problema se presenta en la Figura 1.6.

Transformaciones a la imagen
Figura 1.6
Transformaciones a la imagen

El código para realizar esta transformación es el siguiente (adicional al previo):


Este tipo de problemas se puede solucionar fácilmente cambiando un par de líneas del código anterior. En el código anterior, la transformación se realiza de la imagen original a la imagen nueva (negro), basta cambiar el paradigma y pensar hacia la otra “dirección”. Es decir,

  1. 1. Iteramos sobre cada pixel de la imagen nueva img N.
  2. 2. Trasformamos las coordenadas de i j y obtenemos las coordenadas i ' j ' .
  3. 3. Si i ' j ' no son coordenadas enteras tomamos la parte entera y obtenemos i j .
  4. 4. Colocamos la información en i j de la imagen original en la coordenada i j , i.e.,

    i m g N i j = i m g i j .

El único detalle se presenta es que la trasformación obtenida va a ser la transformación inversa. Por ejemplo, la rotación es en contra de la manecillas del reloj. El código es el siguiente y los resultados se pueden ver en la Figura 1.7.


Transformaciones a la imagen
Figura 1.7
Transformaciones a la imagen

1.4 Compresión de imágenes

Otro ejemplo interesante que aplica el álgebra lineal es el de compresión de datos. El objetivo de la compresión es disminuir la redundancia de datos para poder almacenar o transmitir dichos datos de manera eficiente. En esta sección vamos a considerar una imagen y vamos a utilizar la descomposición en valores singulares (SVD, del inglés singular values decomposition) para su compresión. De hecho, la descomposición SVD tiene un sinnúmero de aplicaciones tales como: resolución de sistemas lineales, aproximación de rango bajo, procesamiento de señales, compresión de información, entre otros.

La descomposición SVD consiste en factorizar una matriz real (o compleja). Consideremos una matriz M de taMaño m × n la descomposición SVD encuentra tres matrices: U de tamaño m × n unitaria ( U U T = I m ) , Σ de tamaño m × n diagonal y V de tamaño m × n unitaria ( V T V = I n ) tales que

M m × n = U m × m Σ m × n V n × n T

Las matrices M y Σ tiene el mismo rango (dimensión del espacio columna). Ahora si suponemos que M = U Σ V T , entonces note que

M M T = ( U Σ V T ) ( U Σ V T ) T = ( U Σ V T ) ( V T Σ T U T ) = U Σ Σ T U T

donde la matriz Σ Σ T . es una matriz diagonal cuyos elementos de la diagonal son los elementos Σ elevados al cuadrado. Así que, para hallar U y Σ basta trabajar con la matriz M M T . la cual es simétrica. Entonces, para determinar las matrices U , Σ , V seguimos los siguientes pasos (para más detalles ver [2, 7]):

  1. 1. Se calcula M M T la cual es una matriz simétrica.
  2. 2. Se resuelve el problema de valores propios ( M M T ) u = λ u . Dado que la matriz M M T es simétrica y por lo tanto definida positiva (siempre tiene solución). Sea el espectro σ = λ 1 λ 2 ... λ m + 0 ordenado de manera decreciente. Por lo tanto podemos definir

    σ i = λ i , i 1 2 . . . m .

  3. 3. Formamos la matriz Σ. Para esto definimos r = mín{m, n} y definimos

    donde

    D=Diag[σ1, σ2, · · · , σr],

    es decir, una matriz diagonal cuyos elementos en la diagonal son los indicados. Y el resto de matrices O son matrices nulas del tamaño indicado.

  4. 4. Para formar U utilizamos los correspondientes vectores propios u i y los colocamos como columnas, es decir U = ( u 1 u 2 · · · u m ) .
  5. 5. Para hallar, usamos la relación Es decir debemos resolver el sistema (para más detalles ver [2,7])

Utilicemos los pasos anteriores en el siguiente ejemplo.




Ahora, observe que podemos escribir la matriz Σ como

Σ = Σ 1 + Σ 2 + · · · + Σ r = i = 1 r Σ i

donde Σ i = D i a g 0 . . . σ i . . . 0 para todo i ∈ {1, 2, · · · , r}. Luego, sabemos que

M = U Σ V t = i = 1 r u i σ i v i T = u 1 σ 1 v 1 T + u 2 σ 2 v 2 T · · · + u r σ r v r T

Los valores de σ i más pequeños están relacionados con la parte de la matriz de menos interés y por lo cual aportarán poca información a la matriz. Entonces, podemos aproximar la matriz M con una matriz de menor rango, digamos de rango p r . Para esto basta definir

M p = i = 1 p u i σ i v i T = u 1 σ 1 v 1 T + u 2 σ 2 v 2 T + · · · + u p σ p v p T

De hecho la matriz M p va a ser la mejor la aproximación de M en la norma 2 (Euclideana)1 de las matrices de rango menor a p . Es decir

ínf { A m × n : r a n g ( A ) p } | | M A | | 2 = | | M M p | | 2 = σ p + 1

Esto es la clave para poder realizar la compresión, por ejemplo, si consideramos los primeros p r valores propios tendremos

M p = U ~ m × p Σ ~ p × p V ~ p × n T

De donde podremos obtener una aproximación de M utilizando menos información. Solo se necesitaría almacenar ( m · n ) + p + ( n · p ) v = p · ( m + n + 1 ) datos en lugar de m × n .

Usando python para hallar la descomposición SVD

Vamos a aprovecharnos de que en python podemos obtener la descomposición SVD simplemente llamando la función svd ( ), la cual toma la matriz M y nos devolverá la matriz U , un vector cuyos elementos son los elementos de la diagonal de Σ y la matriz V T . Por ejemplo, si tomamos los datos de la matriz del ejemplo anterior es decir

M = 1 1 2 - 2 1 1

El código Python es


Las matrices dadas por python son:


Ahora veamos esto aplicado a una imagen. Como la imagen está en formato RGB, sabemos que estamos trabajando con tres matrices, a las cuales vamos a tener que factorizar separadamente, es decir, aplicar la descomposición SVD a cada una de ellas. El código que hace la descomposición y devuelve la imagen aproximada es el siguiente.



Las figuras en 1.8 representan algunas de las imágenes reconstruidas a partir de la descomposición SVD. Definimos p como el número de valores propios que vamos tomar y hemos corrido el programa con p 1, 10, 50, 300, 600, 1000. Esto nos genera seis imágenes que aproximan la original con la ventaja de poder reconstruirla con matrices de menor tamaño, aún para la matriz diagonal Σ basta solo guardar los datos de la diagonal. De este modo, para la imagen de tamaño 2448 × 3264 (7990272 datos) tenemos que


Imágenes reconstruidas con diferentes valores k
Figura 1.8
Imágenes reconstruidas con diferentes valores k

1.5 Conclusión

Sin duda alguna, el álgebra lineal ha dado grandes contribuciones al desarrollo de la matemática y de sus aplicaciones. Los ejemplos que hemos dado en este artículo están muy lejos de ser los únicos, pues existen una enorme cantidad de aplicaciones que podrían mencionarse.

Sabemos que en muchas ocasiones existe una una sensación por parte del estudiantado de que si lo que está aprendiendo (la teoría) tiene alguna aplicación práctica o si simplemente se convertirá en conocimiento que no utilizarán en su vida profesional. Y uno de los objetivos principales de este artículo es romper con este paradigma.

Los ejemplos que se han seleccionado para presentar en este artículo se han elegido debido a que son muy visuales y de uso diario, sobre todo en esta era tecnológica. Hemos visto que usando matrices y transformaciones lineales logramos entender cómo podemos visualizar transformaciones afines y sus aplicaciones directas en el procesamiento digital de imágenes. Además, la descomposición SVD nos permite la compresión de imágenes digitales, lo cual es útil para lograr ahorrar memoria de almacenamiento o para que dichas imágenes puedan ser transmitidas de una forma más eficiente. Esperamos que con este artículo el lector pueda visualizar algunas aplicaciones del álgebra lineal. Pero aún más, esperamos que propicie la motivación del estudio en esta área y la utilización de lenguajes de programación tales como python y, que en lugar de la adquisición de un conocimiento vano en el curso de álgebra lineal este se pueda convertir en una herramienta poderosa.

Bibliografía

Gonzalez, C., Woods, E.(2007) Digital Image Processing. Third Edition. Prentice Hall.

Lay, D., Lay, S., McDonald,J. (2015)Linear algebra and its applications .Fifth Edition.Pearson.

McQuistan, A. (2009).Affine Image Transformations in python with Numpy, Pillow and OpenCV. Recuperado de https://stackabuse.com/affine-image-transformations-in-python-with-numpy-pillow-and-opencv/.

Pesco, U.; Bortolossi,J. Matrix and digital images. 2012. Recuperado de http://dmuw.zum.de/images/6/6d/Matrix-en.pdf.

Schlegel, A. (s.f.).Image Compression with Singular Value Decomposition. Recuperado de https://aaronschlegel.me/image-compression-singular-value-decomposition.html. (Error 1: El enlace externo https://aaronschlegel.me/image-compression-singular-value-decomposition.html. debe ser una URL) (Error 2: La URL https://aaronschlegel.me/image-compression-singular-value-decomposition.html. no esta bien escrita)

Verma, S., Krishna, P. (2013). Image Compression and Linear Algebra. Recuperado de https://www.cmi.ac.in/~ksutar/NLA2013/imagecompression.pdf. (Error 3: El enlace externo https://www.cmi.ac.in/~ksutar/NLA2013/imagecompression.pdf. debe ser una URL) (Error 4: La URL https://www.cmi.ac.in/~ksutar/NLA2013/imagecompression.pdf. no esta bien escrita)

Puntanen, S. (2011). Projection matrices, generalized inverse matrices, and singular value decomposition by haruo yanai, kei takeuchi, yoshio takane. International Statistical Review, 79(3), 503-504.

Putalapattu, R.(s.f.). Jupyter, python, Image compression and svd-An interactive exploration. Recuperado de https://medium.com/@rameshputalapattu/jupyter-python-image-compression-and-svd-an-interactive-exploration-703c953e44f6. (Error 3: El enlace externo https://medium.com/@rameshputalapattu/jupyter-python-image-compression-and-svd-an-interactive-exploration-703c953e44f6. debe ser una URL) (Error 4: La URL https://medium.com/@rameshputalapattu/jupyter-python-image-compression-and-svd-an-interactive-exploration-703c953e44f6. no esta bien escrita)

Notas

1 Definimos la norma 2 de una matriz A m × n como

| | A | | 2 = m á x | | x | | 2 = 1 | | A x | | 2

Enlace alternativo

HTML generado a partir de XML-JATS4R por