#

Estructuras principales de datos#

Las estructuras de datos principales son:

  • Escalares

  • Vectores

  • Matrices

  • Tensores

Diferencias entre escalar, vector, matriz & tensor#

La diferencia entre un escalar, un vector, una matriz y un tensor son los grados de libertad con los que se esta trabajando.

Arreglo

Grados de Libertad

Descripcion

Escalar

0

Es simplemente un numero.

Vector

1

Es un arreglo unidimensional de Escalares

Matriz

2

Es un arreglo bidimensional de vectores

Tensor

3+

Es un arreglo n-dimensional de matrices

Escalar#

Un escalar por definicion es un numero.

En python un escalar puede ser un integer, puede ser un float, puede ser un string o incluso un Null.

porque es un objeto, no un arreglo de objetos

#un escalar (float)
escalar = 5.867

#otro escalar (logical)
escalar_python = True

#y otro escalar (string)
escalar_string = "hi"

Vector#

Un escalar por definicion es un arreglo de escalares.

Puede ser un arreglo de objetos de cualquier tipo.

import numpy as np

#vector (notese que solo hay 1 dimension)
vector = np.array(
    [1, 2, 3, 4]
    )

Funcion para graficar vectores#

import numpy as np
import matplotlib.pyplot as plt

#se crea la funcion para graficar vectores

def graficarVectores(vecs, cols, alpha=1):
    
    plt.figure()
    #se dibuja eje Y
    plt.axvline(x=0, color = "grey", zorder = 0)
    #se dibuja eje X
    plt.axhline(y=0, color = "grey", zorder = 0)

    for i in range(len(vecs)):
        x = np.concatenate([[0,0], vecs[i]])
        plt.quiver(
            [x[0]],
            [x[1]],
            [x[2]],
            [x[3]],
            angles="xy", scale_units="xy", scale=1,
            color = cols[i],
            alpha = alpha
        )

#el vector(es) a graficar, debe pasarse como una lista
#el color(es) a emplear, debe pasarse como una lista de strings
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[3], line 2
      1 import numpy as np
----> 2 import matplotlib.pyplot as plt
      4 #se crea la funcion para graficar vectores
      6 def graficarVectores(vecs, cols, alpha=1):

ModuleNotFoundError: No module named 'matplotlib'

Combinacion lineal#

Una combinacion lineal es:

Picture title

Un proceso en el cual se multiplican dos vectores por dos escalares y al final el resultado se suma es una combinacion lineal.

Se representa graficamente tal que asi:

import numpy as np
import matplotlib.pyplot as plt

#vector 1
v1 = np.array([2,5])
#vector 2
v2 = np.array([3,2])
#combinacion lineal
v1v2 = 2*v1 + 3*v2

graficarVectores([v1, v2, v1v2], ["red", "orange", "yellow"])
plt.xlim(-1, 20)
plt.ylim(-1, 20)
(-1.0, 20.0)
../_images/993ae922972911271b6d2a1766b8543d086ec1e5c2d2e9a28d1d8b187618af9c.png

Todas las posibles combinaciones lineales#

Se hace un grafico que refleje:

  • todas las posibles combinaciones lineales de v1 y v2

  • valores de a y b entre (-10,10)

for a in range(-10, 10):
    for b in range(-10,10):
        plt.scatter(v1[0]*a + v2[0]*b, v1[1]*a + v2[1]*b,
        marker = ".",
        color = "orange")
plt.xlim(-100,100)
plt.ylim(-100,100)

plt.axvline(x=0, color="grey")
plt.axhline(y=0, color="grey")
plt.show()
../_images/523cb6502a53a9e5462180a302461d7afba2ea3fe1c669f5f57d2c6e1be68c31.png

Matriz#

Una matriz es un arreglo de vectores

import numpy as np

#matriz (notese que hay 2 dimensiones) Pueden ser n vectores, pero solo hay 2 dimensiones

matriz = np.array([
    [1,2,3],     #primer vector
    [4,5,6],     #segundo vector
    [7,8,9]      #tercer vector (pueden ser mas)
])

matriz
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

Graficando una matriz con matplotlib#

import matplotlib.pyplot as plt

plt.imshow(matriz, interpolation="nearest")
plt.show()
../_images/234795e6683a06297961734e1f4db50339e2fc3a132bbf9df2033ce378a00724.png

Matriz identidad#

import numpy as np

#Generar matriz identidad

identidad = np.eye(4)       #matriz identidad 4x4
identidad
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])

Inversa de una matriz#

Recuerda que para que una matriz sea invertible, su determinante no puede ser cero.

matrizz = np.array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 10]])

#calculando inversa
matrizz_inv = np.linalg.inv(matrizz)

print("matriz:", matrizz)
print("matriz inversa:", matrizz_inv)
matriz: [[ 1  2  3]
 [ 4  5  6]
 [ 7  8 10]]
matriz inversa: [[-0.66666667 -1.33333333  1.        ]
 [-0.66666667  3.66666667 -2.        ]
 [ 1.         -2.          1.        ]]

determinante de una matriz#

matrizz = np.array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

np.linalg.det(matrizz)
#determinante = 0

#esta matriz no tiene inversa, es una matriz singular 
0.0

Tensor#

Un tensor es un arreglo de matrices

import numpy as np

# Se crea el tensor

# (note que hay 3 dimensiones) Pueden ser n matrices (o n tensores), en este caso solo haremos 2 matrices

tensor = np.array([
    [
        [1,2,3],         #matriz 1
        [4,5,6],
        [7,8,9]
    ],
    [
        [10,11,12],      #matriz 2
        [13,14,15],
        [16,17,18]
    ],
    [
        [19,20,21],      #matriz 3
        [22,23,24],
        [25,26,27]
    ]
])

#imprimir el tensor
tensor
array([[[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9]],

       [[10, 11, 12],
        [13, 14, 15],
        [16, 17, 18]],

       [[19, 20, 21],
        [22, 23, 24],
        [25, 26, 27]]])

Graficando un tensor con matplotlib#

import matplotlib.pyplot as plt

plt.imshow(tensor, interpolation="nearest")
plt.show()
../_images/052974bb1bf13421def8dfe4ce42a5e648041b62538e7fd81f1ebfc4cfef8972.png

No es muy diciente por los numeros que componen el tensor, pero intentemos con un tensor mas diciente

tensor2 = np.array([
    [[0,0,0],[0,0,0],[0,0,0]],                             #0 representa el negro
    [[128,128,128],[128,128,128],[128,128,128]],           #128 lo que hay entre negro y blanco
    [[255,255,255],[255,255,255],[255,255,255]],           #255 representa el blanco
])

plt.imshow(tensor2, interpolation="nearest")
plt.show()
../_images/75bb8ded9114123551f665306fdb69f1e67c4ab84ebd37f7b99eb2446d9d0b78.png

El mejor tensor que veras en tu vida#

Ahora intentemos con un tensor mas elaborado.

#matriz para dibujar los cuadros del fondo
baseMatrix = np.array([
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]]
                     ])

#matriz para dibujar a mario
pixelart = np.array([
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[232,12,12],[221,11,10],[210,0,0],[199,1,0],[200,0,0],[189,5,5],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[221,11,10],[254,0,0],[245,0,10],[245,0,10],[234,0,9],[223,6,14],[223,6,14],[189,5,5],[200,0,2],[210,0,0],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[98,78,43],[106,82,46],[117,92,51],[197,177,144],[209,189,154],[204,184,149],[27,27,27],[197,177,144],[192,192,192],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[98,78,43],[213,194,162],[117,92,51],[213,194,162],[214,197,169],[218,199,167],[213,194,162],[47,47,47],[209,189,156],[204,184,149],[197,177,144],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[92,68,30],[218,199,167],[128,100,60],[214,197,169],[218,199,167],[218,199,167],[213,194,162],[208,189,156],[27,27,27],[208,189,156],[203,183,150],[197,177,144],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[78,57,26],[92,68,30],[197,177,144],[218,199,167],[213,194,162],[208,189,156],[208,189,156],[27,27,27],[47,47,47],[63,63,63],[27,27,27],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192],[204,184,149],[213,194,162],[209,189,154],[204,184,149],[197,177,144],[204,184,149],[204,184,149],[197,177,144],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[221,11,10],[210,0,1],[92,49,224],[200,0,0],[212,0,0],[221,11,10],[42,41,220],[192,192,192],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[232,12,12],[254,0,0],[245,0,10],[84,45,214],[245,0,10],[234,0,9],[83,46,201],[210,0,1],[221,11,10],[232,12,12],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[232,12,12],[254,0,0],[245,0,10],[234,0,9],[84,45,214],[92,49,224],[84,45,214],[77,41,189],[234,0,9],[245,0,10],[254,0,0],[221,11,10],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[197,177,144],[208,191,161],[245,0,10],[84,45,214],[247,223,61],[92,49,224],[83,46,201],[225,202,47],[67,35,172],[232,1,9],[208,191,161],[197,177,144],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[204,184,149],[214,197,169],[197,177,144],[84,45,214],[92,49,224],[84,45,214],[83,46,201],[77,41,189],[67,35,172],[197,177,144],[214,197,171],[204,184,149],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[209,189,154],[204,184,149],[84,45,214],[98,55,233],[92,49,224],[83,46,201],[77,41,189],[83,46,201],[77,41,189],[67,34,173],[204,184,149],[209,189,154],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[128,128,128],[192,192,192],[84,45,214],[84,45,214],[83,46,201],[192,192,192],[128,128,128],[67,35,172],[67,35,172],[67,35,172],[128,128,128],[192,192,192],[128,128,128],[192,192,192]],
                     [[192,192,192],[128,128,128],[192,192,192],[107,83,45],[117,92,51],[111,86,45],[91,67,29],[128,128,128],[192,192,192],[102,78,40],[111,86,45],[103,80,38],[84,61,27],[128,128,128],[192,192,192],[128,128,128]],
                     [[128,128,128],[192,192,192],[107,83,45],[102,78,40],[96,72,34],[91,67,29],[84,61,27],[192,192,192],[128,128,128],[96,72,34],[91,67,29],[84,61,27],[73,54,21],[65,48,18],[128,128,128],[192,192,192]]

])
plt.imshow(pixelart, interpolation='nearest')
plt.show()
../_images/c599c0df77507a94c59a73dd8a6aebd809aaba2aee09f18d864f41e6b9660ab0.png

Operaciones algebraicas#

Se definen las siguientes estructuras para trabajar

import numpy as np

vector = np.array(
    [1, 2, 3, 4]
    )

matriz = np.array([
    [1,2,3],     
    [4,5,6],    
    [7,8,9]  
])

tensor = np.array([
    [
        [1,2,3],        
        [4,5,6],
        [7,8,9]
    ],
    [
        [10,11,12],     
        [13,14,15],
        [16,17,18]
    ],
    [
        [19,20,21],     
        [22,23,24],
        [25,26,27]
    ]
])

Transpuesta#

con la funcion .T al final del arreglo, se obtiene su transpuesta

Transpuesta en vector#

Una transposicion de vectores convierte un vector fila en un vector columna o visceversa.

print("vector original", vector)
print("vector transpuesto:", vector.T)
vector original [1 2 3 4]
vector transpuesto: [1 2 3 4]

Transpuesta en Matriz#

Una transpuesta de matrices, la invierte con respecto a su diagonal.

print("matriz original:")
print(matriz)
print("matriz transpuesta:")
print(matriz.T)
matriz original:
[[1 2 3]
 [4 5 6]
 [7 8 9]]
matriz transpuesta:
[[1 4 7]
 [2 5 8]
 [3 6 9]]

Transpuesta en Tensor#

print("tensor original:")
print(tensor)
print("tensor transpuesto:")
print(tensor.T)
tensor original:
[[[ 1  2  3]
  [ 4  5  6]
  [ 7  8  9]]

 [[10 11 12]
  [13 14 15]
  [16 17 18]]

 [[19 20 21]
  [22 23 24]
  [25 26 27]]]
tensor transpuesto:
[[[ 1 10 19]
  [ 4 13 22]
  [ 7 16 25]]

 [[ 2 11 20]
  [ 5 14 23]
  [ 8 17 26]]

 [[ 3 12 21]
  [ 6 15 24]
  [ 9 18 27]]]

Producto punto#

Para poder hacer un producto punto entre dos matrices o entre una matriz y un vector, se debe cumplir la siguiente condicion:

Picture title

Numero de columnas del primer vector = Numero de filas del segundo vector

De otra forma, no se puede hacer producto punto. Tal como en la siguiente imagen:

Picture title

Funcion para producto punto en python#

Para hacer producto punto en python, se usa la funcion .dot()

import numpy as np
A = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
B = np.array([[2,3],[5,7],[11,13]])

C = A.dot(B)

C
array([[ 45,  56],
       [ 99, 125],
       [153, 194],
       [207, 263]])

Sistemas de ecuaciones como matrices#

Matriz inversa para resover sistema de ecuaciones#

Supongamos el siguiente sistema de ecuaciones:

drawing
import numpy as np

# Se establece que cualquier valor muy cercano a cero, se haga cero. Esto para
# identificar mas facilmente la matriz identidad.

np.set_printoptions(suppress=True)

#matriz A
A = np.array([[3,1], [2,1]])

#matriz B
B = np.array([[1],[1]])

Ahora para hallar el vector que soluciona este sistema de ecuaciones:

A_inv = np.linalg.inv(A)


#solucion: se multiplica la inversa de A por el vector B
x = A_inv.dot(B)

Se comprueba la solucion evaluando la expresion de la izquierda de la igualdad

print(A.dot(x))
[[1.]
 [1.]]

Verificar si un sistema de ecuaciones tiene solucion#

Picture title

import numpy as numpy
import matplotlib.pyplot as plt

# se crea un eje x
x = np.arange(-6, 6)

# primera ecuacion
y_1 = -1*x + 3
#segunda ecuacion
y_2 = 2*x + 5

Ahora se grafica el sistema para ver si tiene solucion

#se grafican las rectas
plt.plot(x, y_1)
plt.plot(x, y_2)

# se limita el eje X y el eje Y para enfatizar solo una zona
plt.xlim(-8,8)
plt.ylim(-8,8)

# se dibuja el eje X y el eje Y
plt.axvline(x=0, color="grey")
plt.axhline(y=0, color="grey")

plt.show()
../_images/9450b3d8cd91e97c210bfb5dabaf8c0d93b4cef1b71955f3968f84b15b3c7f91.png

Si tiene solucion, y esta es los valores de X & Y que hacen que las rectas se intersecten.

Sistemas de ecuaciones sin solucion#

Sistemas sobredeterminados#

Imagine el sistema

drawing
import numpy as numpy
import matplotlib.pyplot as plt

# se crea un eje x
x = np.arange(-6, 6)

# primera ecuacion
y_1 = 3*x + 5
#segunda ecuacion
y_2 = -x + 3
#tercera ecuacion
y_3 = 2*x + 1

ahora se grafican las tres rectas

#se grafican las rectas
plt.plot(x, y_1)
plt.plot(x, y_2)
plt.plot(x, y_3)

# se limita el eje X y el eje Y para enfatizar solo una zona
plt.xlim(-8,8)
plt.ylim(-8,8)

# se dibuja el eje X y el eje Y
plt.axvline(x=0, color="grey")
plt.axhline(y=0, color="grey")

plt.show()
../_images/bf3642d5984996bd6877edd6f03739459a102a999e0e1752c11e7af17aed1511.png

Dado que las tres rectas no convergen a ningun punto en comun, el sistema no tiene solucion.

import numpy as np
import matplotlib.pyplot as plt

#se crea la funcion para graficar vectores

def graficarVectores(vecs, cols, alpha=1):
    
    plt.figure()
    #se dibuja eje Y
    plt.axvline(x=0, color = "grey", zorder = 0)
    #se dibuja eje X
    plt.axhline(y=0, color = "grey", zorder = 0)

    for i in range(len(vecs)):
        x = np.concatenate([[0,0], vecs[i]])
        plt.quiver(
            [x[0]],
            [x[1]],
            [x[2]],
            [x[3]],
            angles="xy", scale_units="xy", scale=1,
            color = cols[i],
            alpha = alpha
        )

#el vector(es) a graficar, debe pasarse como una lista
#el color(es) a emplear, debe pasarse como una lista de strings

Graficar sistemas de ecuaciones como vectores#

import numpy as np
import matplotlib.pyplot as plt

#se crea la funcion para graficar vectores

def graficarVectores(vecs, cols, alpha=1):
    
    plt.figure()
    #se dibuja eje Y
    plt.axvline(x=0, color = "grey", zorder = 0)
    #se dibuja eje X
    plt.axhline(y=0, color = "grey", zorder = 0)

    for i in range(len(vecs)):
        x = np.concatenate([[0,0], vecs[i]])
        plt.quiver(
            [x[0]],
            [x[1]],
            [x[2]],
            [x[3]],
            angles="xy", scale_units="xy", scale=1,
            color = cols[i],
            alpha = alpha
        )

#el vector(es) a graficar, debe pasarse como una lista
#el color(es) a emplear, debe pasarse como una lista de strings
v1 = np.array([2,5])
v2 = np.array([3,2])

graficarVectores([v1, v2], ["red", "blue"])
#se ajustan los limites x & y para mejor visibilidad
plt.xlim(-1, 8)
plt.ylim(-1, 8)
(-1.0, 8.0)
../_images/81f58c9204bc945fde2f3194794b05d8b090fe4f603185ac7a47c3bfb5ddde1f.png

Matrices como combinaciones lineales#

Imagina que tienes el vector [2,1] y lo quieres transformar en [1,2] mediante el uso de una matriz:

drawing

Hay que buscar una matriz A tal que:

  • \(A\) X \([2,1] = [1,2]\)

import numpy as np
import matplotlib.pyplot as plt

#matriz A
A = np.array([[-1,3], [2,-2]])
print(A)

# vector [2,1]
vector = np.array([[2], [1]])
print(vector)
[[-1  3]
 [ 2 -2]]
[[2]
 [1]]

se grafica el vector A

recordar que la funcion graficarVectores (definida en capitulo 1.iii.a) recibe los vectores en forma de lista.

  • Se usa .flatten() para transformar al vector

vector.flatten()
array([2, 1])

El vector.flatten() si se puede introducir en la funcion:

graficarVectores([vector.flatten()], cols = "blue")
plt.xlim(-0.5, 3)
plt.ylim(-0.5, 2)
(-0.5, 2.0)
../_images/d1600255b052a3bc3a6f3a620c5578e5aaa656aebce43a5fa247ca88eca669d2.png

Ahora se multiplica

\(A\) x \([2,1]\)

para lograr la transformacion deseada

vector_transformado = A.dot(vector)
print(vector_transformado)
[[1]
 [2]]

Se grafican al vector original y al vector transformado

graficarVectores([vector.flatten(), vector_transformado.flatten()], ["red", "blue"])
plt.xlim(-0.5, 3)
plt.ylim(-0.5, 2)
(-0.5, 2.0)
../_images/c9e672e71f71792a3763d1b7f3adc6ac99aead29b2e278ee42b18460f24fff73.png

Autovectores y Autovalores#

Sea X una matriz cuadrada (NxN)

  • Un autovector \(\overrightarrow{V}\) es un vector tal que:

\(X*\overrightarrow{V} = \lambda*\overrightarrow{V} \)

Es decir:

  • el producto punto \(X*\overrightarrow{V}\) devuelve un autovector (\(\lambda*\overrightarrow{V}\))

  • \(\lambda\) es el correspondiente autovalor

  • el autovector tiene la misma direccion que el vector original pero distinta longitud.

Una matriz NxN tiene asociados N autovalores, por ende N autovectores

drawing
import numpy as np
import matplotlib.pyplot as plt

# matriz cuadrada X
X = np.array([[3,2], [4,1]])
print(X)

#vector original
v = np.array([[1], [1]])

# vector lambda*v
u = X.dot(v)
[[3 2]
 [4 1]]

Ahora se grafican el vector original y el vector transformado para ver mejor el resultado

#se definen unos colores para el grafico
orange_light = "#FF9A13"
blue_light = "#1190FF"

#se grafican el vector original y el modificado
graficarVectores([u.flatten(), v.flatten()], cols=[orange_light, blue_light])

plt.xlim(-1, 6)
plt.ylim(-1, 6)
(-1.0, 6.0)
../_images/b7e4b9f78b08eea9cf1ee3c442b672f7e26db4f0fbd578e37a8f5de28f9241d9.png

Entonces, para este ejemplo particular:

  • autovalor(\(\lambda\)) = 5

  • autovector(\(\lambda*\overrightarrow{V} \)) = \(5*\overrightarrow{V} \) = [5,5]

ahora intentemos con otra combinacion de \(\lambda\) y \(\overrightarrow{V} \)

en esta ocasion el vector se llama \(\overrightarrow{S}\)

# vector original
s = np.array([[-1], [2]])

# vector transformado (producto punto de X con s)
t = X.dot(s)

Ahora se procede a graficar el vector original y el vector transformado:

graficarVectores([t.flatten(), s.flatten()], cols=[orange_light, blue_light])

plt.xlim(-3, 3)
plt.ylim(-3, 3)
(-3.0, 3.0)
../_images/11eeba0ea8bede7d373f8d18588e0679978e997f91e19f179afc50de426d8395.png

Entonces, para este segundo ejemplo:

  • autovalor(\(\lambda\)) = -1

  • autovector(\(\lambda*\overrightarrow{V} \)) = \(-1*\overrightarrow{S} \) = [1,-2]

Se comprueba entonces:

Para una matriz de 2x2 (matriz X en este caso) hay dos autovalores y dos autovectores asociados.

Calcular autovalores y autovectores#

Imagina que tienes la matriz X del ejercicio anterior, pero esta vez no tienes los autovalores ni los autovectores.

Como se calculan?

import numpy as np
import matplotlib.pyplot as plt

X = np.array([[3,2], [4,1]])

# se calculan los eigen values
print(np.linalg.eig(X))
(array([ 5., -1.]), array([[ 0.70710678, -0.4472136 ],
       [ 0.70710678,  0.89442719]]))

Como puedes ver, inicialmente el codigo te devuelve una primera lista con autovalores. La segunda lista contiene los autovectores.

Para guardar los autovalores y autovectores en objetos, se asigna asi:

autovalores, autovectores = np.linalg.eig(X)

print(autovalores)

#primer autovector
print(autovectores[:, 0])

#segundo autovector
print(autovectores[:, 1])

#Notese que los autovectores cobran sentido en la columna
[ 5. -1.]
[0.70710678 0.70710678]
[-0.4472136   0.89442719]

Por que los autovectores no son iguales a los del ejercicio anterior?

Vamos a confirmarlo

grafiquemos

  • vector original

  • autovector obtenivo previamente

  • autovector obtenido por np.linalg.eig

# vector original
v = np.array([[-1], [2]])

#autovector np.linalg.eig
Xv = autovectores[:,1]

# t es el autovector obtenido de multiplicar X*s en el ejercicio anterior

graficarVectores([v.flatten(), Xv.flatten(), t.flatten()], ["red", "blue", "yellow"])
plt.ylim(-4,2)
plt.xlim(-7,3)
(-7.0, 3.0)
../_images/766d01facfa3508d0561b7a4f3033321e0dad2e404d800f8d3b3210bf4b2158d.png

Entiendase que los tres siguen siendo el mismo vector, pero con una magnitud diferente.

  • El autovector encontrado por np.linalg.eig() es un multiplo del autovector propuesto en el ejercicio anterior.

Descomposicion de matrices#

Una matriz se puede escribir en funcion de sus autovalores y autovectores (solo si es cuadrada).

Una matriz es igual a:

  • Matriz de autovectores X Matriz diagonal de autovalores X [Matriz de autovectores]^-1

drawing
import numpy as np

A = np.array([[3,2], [4,1]])

autovalores, autovectores = np.linalg.eig(A)

Entonces, teniendo los autovectores y los autovalores se puede reconstruir la matriz

A_recons = autovectores.dot(np.diag(autovalores)).dot(np.linalg.inv(autovectores))

A_recons
array([[3., 2.],
       [4., 1.]])

Ahora, si la matriz es real(contiene numeros reales) y simetrica(A = A.T), entonces la igualdad es

B = np.array([[3,2], [2,3]])

autovalores2, autovectores2 = np.linalg.eig(B)

B_recons = autovectores2.dot(np.diag(autovalores2)).dot(autovectores2.T)

B_recons
array([[3., 2.],
       [2., 3.]])

Computacionalmente es mas costoso calcular una inversa que una transpuesta.

Entonces siempre es deseado tener una matriz simetrica.

Descomposicion de matrices no cuadradas (SVD)#

El metodo SVD descompone una matriz no cuadrada en tres matrices U, V, D:

  • U contiene todos los vectores izquierdos singulares

  • V contiene todos los vectores derechos singulares

U y V son ortogonales (Todos sus vectores son ortonormales)

  • D es una matriz diagonal (Todos los valores de la diagonal son valores singulares)

La matriz original se reescribe como:

U x D x V

import numpy as np

C = np.array([[1,2,3], [3,4,5]])

# Descomposicion en valores singulares:
U, D, V = np.linalg.svd(C)

vectores izquierdos singulares

U
array([[-0.46410668, -0.88577931],
       [-0.88577931,  0.46410668]])

Matriz diagonal(diagonal de valores singulares)

D
array([7.97638869, 0.61418515])
D_modified = np.array([[D[0],0,0],[0,D[1],0]])

D_modified
array([[7.97638869, 0.        , 0.        ],
       [0.        , 0.61418515, 0.        ]])

vectores derechos singulares

V
array([[-0.39133557, -0.5605708 , -0.72980603],
       [ 0.8247362 ,  0.13817999, -0.54837623],
       [ 0.40824829, -0.81649658,  0.40824829]])

Finalmente se reescribe la matriz original:

C_calc = U.dot(D_modified).dot(V)

C_calc
array([[1., 2., 3.],
       [3., 4., 5.]])

Creacion de funcion para graficar circulo unitario#

import numpy as np
import matplotlib.pyplot as plt

#creacion de funcion que grafique el ciculo unitario
def graficarMatriz(matriz, vectorCol=["red", "blue"]):

    #circulo unitario
    x = np.linspace(-1, 1, 100000)
    y = np.sqrt(1 - (x**2))

    #circulo unitario transformado
    x1 = matriz[0, 0]*x + matriz[0,1]*y
    y1 = matriz[1, 0]*x + matriz[1,1]*y
    x1_neg = matriz[0,0]*x - matriz[0,1]*y
    y1_neg = matriz[1,0]*x - matriz[1,1]*y

    #se usa la funcion graficar vectores para mostrar los vectores tambien
    u1 = [matriz[0,0], matriz[1,0]]
    v1 = [matriz[0,1], matriz[1,1]]
    graficarVectores([u1, v1], cols=[vectorCol[0], vectorCol[1]])

    plt.plot(x1, y1, "green", alpha = 0.7)
    plt.plot(x1_neg, y1_neg, "green", alpha = 0.7)

Ahora se imprime el circulo unitario y el circulo unitario transformado al mismo tiempo

print("Circulo unitario:")
graficarMatriz(np.eye(2))

plt.xlim(-1.5, 1.5)
plt.ylim(-1.5, 1.5)
plt.show()

# se define un vector A
A = np.array([[3, 7], [5, 2]])
print("Circulo unitario transformado:")
graficarMatriz(A)

plt.xlim(-8, 8)
plt.ylim(-8, 8)
plt.show()
Circulo unitario:
../_images/6ccdee814cb4b74f9c6f85fbbd60a541730408623592fa7ac23bb9b26c6c5d47.png
Circulo unitario transformado:
../_images/cb1c5e54dddc0df23185cf00e253b3f8f2611c66cc8be85cfcd97892ff532417.png

Analizando transformaciones de matrices U-D-V en circulo unitario#

Dado que una matriz se puede ver como una combinacion lineal de sus vectores propios y sus valores propios, se analiza el efecto de estos en la matriz original.

Se grafica el circulo unitario original:

print("Circulo unitario:")
graficarMatriz(np.array([[1, 0], [0, 1]]))

plt.xlim(-1.5, 1.5)
plt.ylim(-1.5, 1.5)
plt.show()
Circulo unitario:
../_images/6ccdee814cb4b74f9c6f85fbbd60a541730408623592fa7ac23bb9b26c6c5d47.png

Ahora se analiza el efecto del vector propio V (Rota los vectores originales)

#Descomposicion
U, D, V = np.linalg.svd(A)

print("Primer Rotacion (V):")
graficarMatriz(V)

plt.xlim(-1.5, 1.5)
plt.ylim(-1.5, 1.5)
plt.show()
Primer Rotacion (V):
../_images/e24240311e6e8f29d9ef84592913b039f77d6f23dd4982a06e7b4598726b8a23.png

Ahora se grafica el efecto de la matriz diagonal de valores propios D (Modifica la escala. Es decir, agranda los valores en alguna dimension y los reduce en otra):

print("Escala (D):")
graficarMatriz(np.diag(D).dot(V))

plt.xlim(-9, 9)
plt.ylim(-9, 9)
plt.show()
Escala (D):
../_images/b39d27e1c7d9f6c7e0f6cff45aac22c1d76ecfa99ce0d41c4f2ebfeba7764fa7.png

Por ultimo, el vector U hace una ultima rotacion:

print("Segunda Rotacion (U):")
graficarMatriz(U.dot(np.diag(D).dot(V)))

plt.xlim(-8, 8)
plt.ylim(-8, 8)
plt.show()
Segunda Rotacion (U):
../_images/cb1c5e54dddc0df23185cf00e253b3f8f2611c66cc8be85cfcd97892ff532417.png

Efecto de autovalores(D) sobre los autovectores#

Se crea una matriz A y se descompone en sus respectivos autovalores y autovectores.

A = np.array([[3, 7], [5,2]])

U, D, V = np.linalg.svd(A)

print(D)
print(U)
[8.71337969 3.32821489]
[[-0.85065081 -0.52573111]
 [-0.52573111  0.85065081]]

Ahora se mira el efecto de la matriz de autovalores sobre la matriz transformada de autovectores:

u1 = [D[0]*U[0,0], D[0]*U[0,1]]
v1 = [D[1]*U[1,0], D[1]*U[1,1]]

#La matriz original (A) vs la matriz transformada (A afectada por los autovalores)
print([A[0,0], A[1,0]])
print(u1)
print()
print([A[0,1], A[1,1]])
print(v1)
[3, 5]
[-7.4120434792975685, -4.580894796297923]

[7, 2]
[-1.7497461132982814, 2.8311486829996433]
graficarMatriz(A)
graficarVectores([u1, v1], cols = ["red", "blue"])

plt.text(3, 5, r"$u_1$", size = 18)
plt.text(7, 2, r"$v_1$", size = 18)

plt.text(-5, -4, r"$D(u_1)$", size = 18)
plt.text(-4, 1, r"$D(v_1)$", size = 18)

plt.xlim(-8, 8)
plt.ylim(-8, 8)
plt.show()
../_images/f4c85f8126f48941c0dac379b0b9c9df2478cb2f9601bd98470ac509924966de.png ../_images/7b341b55919575fa3e663cbb39dcd2e94da56813dad698171be4c4fee0bf5259.png

Imágenes como matriz#

Con la funcion Image del modulo PIL, convertimos un archivo JPG en un archivo de tipo PIL que puede ser transformado en matriz o convertido en imagen.

Objeto de tipo PIL#

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

# Se importa la imagen
imagen = Image.open("imagen_ejemplo_frida_bredesen.jpg")

print(imagen)
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=3693x3456 at 0x7FA3590FBB20>

Lo que nos acaba de mostrar es que esto es un objeto de tipo PIL.

Para mostrar la imagen el comando es:

Mostrar imagen de tipo PIL#

plt.imshow(imagen)
plt.show()
../_images/b303a4f34b221a2323d4ab454dbc00c2b2d571a946d9cb8fa3e176115686e15e.png

Convertir a escala de grises#

imagen_gr = imagen.convert("LA")
plt.imshow(imagen_gr)
plt.show()
../_images/20190887cb24159e6d83e981826030761f333d1d43ef634081dab198c531bb29.png

En realidad lo que ve el computador es una matriz (o muchas matrices)

Se tranforma el objeto en matriz:

Transformar a matriz#

imagen_mat = np.array(list(imagen_gr.getdata(band=0)), float)
print(imagen_mat)

#veamos las dimensiones de la matriz
print(imagen_mat.shape)
[236. 236. 235. ... 195. 195. 193.]
(12763008,)

Cambiar dimensiones de la matriz#

  • originalmente la matriz tiene dimensiones (mxn, 1)

  • se cambia a dimensiones (m, n)

imagen_mat.shape = (imagen_gr.size[1], imagen_gr.size[0])

print(imagen_mat.shape)

print(imagen_mat)
(3456, 3693)
[[236. 236. 235. ... 239. 239. 239.]
 [236. 236. 235. ... 239. 239. 239.]
 [236. 236. 235. ... 238. 238. 238.]
 ...
 [217. 216. 216. ... 197. 196. 194.]
 [216. 216. 216. ... 196. 195. 193.]
 [216. 216. 216. ... 195. 195. 193.]]

Modificar valores de matriz#

Al ser un array, se pueden jugar con los valores internos de la matriz

# Todos los valores sobre 10
imagen_mat2 = imagen_mat/10
plt.imshow(imagen_mat2)
plt.show()
../_images/a2be96a90867b4abb12f0558e644e1c55b0f741a1a2c4f65eee732964bd5730e.png

Pero incluso, despues de modificar los valores originales de la matriz, se puede imprimir nuevamente en escala de grises

plt.imshow(imagen_mat2, cmap="gray")
plt.show()
../_images/d4213b20fdfba79f67353495ea0e070a8951a9cc251a65de0661ff465ed27c1e.png

Valores entre cero y uno a partir de matriz#

Se divide todo el array entre el valor maximo de este para obtener valores entre cero y uno

imagen_mat3 = imagen_mat/(np.max(imagen_mat))
plt.imshow(imagen_mat3)
plt.show()
../_images/a2be96a90867b4abb12f0558e644e1c55b0f741a1a2c4f65eee732964bd5730e.png

Demostremos que todos los valores estan entre cero y uno

# Valor minimo
print(np.min(imagen_mat3))

# Valor maximo
print(np.max(imagen_mat3))
0.10245901639344263
1.0

Descomposicion SVD de imagenes#

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

#importar la imagen
imagen = Image.open("imagen_ejemplo_frida_bredesen.jpg")

#convertir a grises
imagen_gr = imagen.convert("LA")

#convertir a matriz
imagen_mat = np.array(list(imagen_gr.getdata(band=0)), float)

#dar dimensiones
imagen_mat.shape = (imagen_gr.size[1], imagen_gr.size[0])

Obteniendo vectores U,D,V#

# descomposicion en valores singulares
U, D, V = np.linalg.svd(imagen_mat)

Se muestran las dimensiones de U, D & V:

print(imagen_mat.shape)
print(U.shape)
print(D.shape)
print(V.shape)
(3456, 3693)
(3456, 3456)
(3456,)
(3693, 3693)

Reconstruir la imagen usando vectores U,D,V#

Se reconstruye la imagen con los valores singulares

note que en este caso se usa 1 valores singulares

imagen_recons = np.matrix(U[:, :1])*np.diag(D[:1])*np.matrix(V[:1,:])

plt.imshow(imagen_recons, cmap="gray")
plt.show()
../_images/02b0ba45aef4dd712a390816b7eacfe785b9c948bcc5c95cf959b5cf7e04242a.png

Usando 5 valores singulares#

# Se construye nuevamente la imagen
# esta vez se hace con i valores singulares
i = 5
imagen_recons = np.matrix(U[:, :i])*np.diag(D[:i])*np.matrix(V[:i,:])

# se crea un titulo
titulo = "valores singulares = %s" %i

#ahora veamos la imagen
plt.imshow(imagen_recons, cmap="gray")
plt.title(titulo)
plt.show()
../_images/28613662737194f98f87b369f9dd5d14163c86a7803cdb172059bbe28716f031.png

Usando 10 valores singulares#

# Se construye nuevamente la imagen
# esta vez se hace con i valores singulares
i = 10
imagen_recons = np.matrix(U[:, :i])*np.diag(D[:i])*np.matrix(V[:i,:])

# se crea un titulo
titulo = "valores singulares = %s" %i

#ahora veamos la imagen
plt.imshow(imagen_recons, cmap="gray")
plt.title(titulo)
plt.show()
../_images/44dbd6069ad2b21a07a382b1ad569133fabf53aef1bf47e577df1699119a45d8.png

Usando 25 valores singulares#

# Se construye nuevamente la imagen
# esta vez se hace con i valores singulares
i = 25
imagen_recons = np.matrix(U[:, :i])*np.diag(D[:i])*np.matrix(V[:i,:])

# se crea un titulo
titulo = "valores singulares = %s" %i

#ahora veamos la imagen
plt.imshow(imagen_recons, cmap="gray")
plt.title(titulo)
plt.show()
../_images/c6305c0b65bc6a1b64134137cce4f8e6e04fa0e9b2d503f24ae3945e5d191379.png

Usando 50 valores singulares#

# Se construye nuevamente la imagen
# esta vez se hace con i valores singulares
i = 50
imagen_recons = np.matrix(U[:, :i])*np.diag(D[:i])*np.matrix(V[:i,:])

# se crea un titulo
titulo = "valores singulares = %s" %i

#ahora veamos la imagen
plt.imshow(imagen_recons, cmap="gray")
plt.title(titulo)
plt.show()
../_images/afa6525fcc3428fb395c8256d6026bd4e5626cf2daf0fe6bac64502dd8063cf3.png

Pseudoinversa de Moore Penrose#

La inversa de una matriz tiene la propiedad que

\(A * A\)-1 \(= Matriz Identidad\)

con la condicion que A sea invertible, es decir, det(A) != 0

Pero que pasa si la matriz no es invertible?

Bueno, entonces existe la pseudoinversa de moore penrose, que tiene la propiedad que

\(A * A\)pse \( \approx Matriz identidad \)

es decir es aproximadamente la matriz identidad

Como se calcula la pseudoinversa de moore penrose?#

numpy ya tiene una funcion que lo hace automaticamente, pero se hace manualmente para entender el concepto

Primero se hacer la descomposicion en vecotres y valores propios de la matriz original

recordad que el comando era:

U, D, V = np.linalg.svd(A)

posteriormente, la matriz Apse es se define:

\(A\)pse \(= V * D\)pse\(* U.T\)

import numpy as np

# Esta linea le dice a numpy que no imprima numeros muy cercanos a cero
np.set_printoptions(suppress=True)

A = np.array([[2,3], [5,7], [11,13]])

print(A)
[[ 2  3]
 [ 5  7]
 [11 13]]
U, D, V = np.linalg.svd(A)

print("U")
print(U)
print("D")
print(D)
print("V")
print(V)
U
[[-0.18499741 -0.47276624 -0.86154979]
 [-0.44249308 -0.74271297  0.50257071]
 [-0.87748267  0.4742041  -0.07179582]]
D
[19.40321383  0.71783924]
V
[[-0.63055377 -0.77614557]
 [ 0.77614557 -0.63055377]]

Calculando D_pse#

  1. Se hace una matriz de ceros con la misma dimension de A transpuesta

D_pse = np.zeros( ( A.shape[0],A.shape[1] ) ).T

D_pse
array([[0., 0., 0.],
       [0., 0., 0.]])
  1. los valores que se reemplazan en D_pse son los valores de la inversa de la matriz diagonal D

# Esta es la inversa de la matriz diagonal D
np.linalg.inv(np.diag(D))
array([[0.05153785, 0.        ],
       [0.        , 1.39306957]])
# y aqui estamos reemplazando
D_pse[:D.shape[0], :D.shape[0]] = np.linalg.inv(np.diag(D))

# El resultado:
D_pse
array([[0.05153785, 0.        , 0.        ],
       [0.        , 1.39306957, 0.        ]])

Reconstruyendo A_pse#

A_pse = V.T.dot(D_pse).dot(U.T)

A_pse
array([[-0.50515464, -0.78865979,  0.54123711],
       [ 0.42268041,  0.67010309, -0.3814433 ]])

Comparando A_pse manual con A_pse de numpy#

# Matriz pseudoinversa manual
print("A_pse calculada manualmente")
print(A_pse)

#Matriz pseudoinversa de numpy
print("A_pse calculada con numpy")
A_pse_numpy = np.linalg.pinv(A)
print(A_pse_numpy)
A_pse calculada manualmente
[[-0.50515464 -0.78865979  0.54123711]
 [ 0.42268041  0.67010309 -0.3814433 ]]
A_pse calculada con numpy
[[-0.50515464 -0.78865979  0.54123711]
 [ 0.42268041  0.67010309 -0.3814433 ]]

Usando Pseudoinversa para resolver sistema de ecuaciones sobredeterminado#

Un sistema de ecuaciones se puede representar como

\(Ax = b\)

En el caso que A tenga inversa, la solucion es:

\(x =\) A-1 \(b\)

pero que ocurre cuando A no tiene inversa?

Entonces el sistema tiene infinitas soluciones, aun asi se puede usar la pseudoinversa \(A\)pse para dar una solucion que aunque no es exacta, minimiza la norma dos de la expresion Ax-b. La mision es entonces:

  • Encontrar un x tal que ||Ax-b||2 sea minimo ||Ax-b||2 es la Norma 2 de Ax-b

y en ese caso, la solucion es:

\(x =\) Apse \(b\)

ejemplo:

Definiendo sistema de ecuaciones#

import numpy as np
import matplotlib.pyplot as plt

# se define el eje x
x = np.linspace(-5, 5, 1000)

# se definen las tres rectas

y1 = -4*x + 3
y2 =  2*x + 5
y3 = -3*x + 1

En este caso se tienen 2 variables y 3 ecuaciones, por lo que este sistema esta sobredeterminado

plt.plot(x, y1)
plt.plot(x, y2)
plt.plot(x, y3)

plt.xlim(-2, 2.5)
plt.ylim(-6, 6)

plt.show()
../_images/872b9263687145dcea3b99472bb9243215bb5dfa8b469ccc30ec62cb5edf3f54.png

Las tres rectas no convergen en un unico punto, de hecho son dos. Por lo cual el sistema esta sobredeterminado.

Se quiere hallar la solucion del sistema de ecuaciones Ax = b, tal que x hace que ||Ax-b||2 sea minima.

Convertir las rectas en matrices#

las rectas son:

\(y = -4x + 3\) \(y = 2x + 5\) \(y = -3x + 1\)

separando las constantes de las variables:

\(4x + y1 = 3\) \(-2x + y2 = 5\) \(3x + y3 = 1\)

Entonces, la matriz A es:

A = np.array([[4, 1], [-2, 1], [3, 1]])

A
array([[ 4,  1],
       [-2,  1],
       [ 3,  1]])

A su vez, el vector solucion es:

b = np.array([[3], [5], [1]])

b
array([[3],
       [5],
       [1]])

Calculando la solucion#

Recuerda que la solucion es:

\(x = A\)pse\(b\)

# Matriz pseudoinversa
A_pse = np.linalg.pinv(A)

# a x la llamaremos "resultado"
resultado = A_pse.dot(b)

#imprimir resultado
resultado
array([[-0.48387097],
       [ 3.80645161]])

Interpretando la solucion graficamente#

plt.plot(x, y1)
plt.plot(x, y2)
plt.plot(x, y3)

plt.xlim(-2, 2.5)
plt.ylim(-6, 6)

plt.scatter(resultado[0], resultado[1])

plt.show()
../_images/c458327d5780c8bc493afe16a89ace8544d74d77f9230be6649e5544d2799d52.png

El punto que nos está devolviendo, no está en el centro, las ecuaciones tienen distintos pesos. cada una está atrayendo el punto hacia sí misma

PCA (Analisis de componentes principales)#

Se procede a generar un dataset con dos variables X & Y

  • \(X\) una columna de numeros aleatorios entre 0 y 3

  • \(Y = 20X + error\)

import numpy as np
import matplotlib.pyplot as plt

# Se define valor semilla para obtener aleatorios igules en cada ejecucion
np.random.seed(42)

x = 3*np.random.rand(200)

y = 20*x + 2*np.random.randn(200)    #Se agrega un error

# Se le da formato de columna a las dos variables
x = x.reshape(200,1)
y = y.reshape(200,1)

# Se unen los dos vectores como uno solo
xy = np.hstack([x, y])

De esta forma se tienen las dos variables X & Y, vamos a graficarlas

plt.plot(xy[:,0], xy[:,1], ".")
plt.show()
../_images/773d09ebef7b0a4d742ce4e25eb81f169e494a373ec30a5efc695df129fe6115.png

Ahora se verifica cuanta varianza captura cada eje, para posteriormente escoger solamente un eje

  • Se procede a centrar el grafico anterior

xy_centrado = xy - np.mean(xy, axis = 0)

plt.plot(xy_centrado[:,0], xy_centrado[:,1], ".")
plt.show()
../_images/ce7b187921ab60ee538285ba5c16b15947960b06ebc49ab7c052e948f2b74f68.png

Ahora, para poder encontrar las componentes principales

Hay que calcular las componentes que buscan un d tal que:

drawing
  • d tal que retorne maximo de la traza de d transpuesto \(*\) x transpuesto \(*\) xd

Ademas hay otra restriccion, hay que pedir que el resultado tenga norma 1. Es decir:

drawing

Para poder hacer nuestra transformacion, se calculan los autovalores y los autovectores

autovalores, autovectores = np.linalg.eig(xy_centrado.T.dot(xy_centrado))

print(autovectores)
[[-0.9987754  -0.04947417]
 [ 0.04947417 -0.9987754 ]]
  • cada columna esta asociada con un autovalor

  • el vector asociado con el autovalor mas grande indica la direccion de maxima varianza.

Se grafican los vectores:

# autovectores transpuestos porque los autovectores se interpretan a nivel de columna
graficarVectores(autovectores.T, ["blue", "red"])

# pongamos en el mismo grafico la nube de puntos
plt.plot(xy_centrado[:,0], xy_centrado[:,1], ".")

plt.show()
../_images/a8f8fe33a1ad4f995826818341e356aa629b622fa6d1c3dd3020bfc8b30b070f.png

hay un autovector con una amplitud muy pequeña, vamos a amplificarlo (Reduciendo la escala del grafico)

Esto no afecta el resultado final porque: No importa la amplitud del autovector, sino cual es el autovector relacionado al autovalor mas grande

# autovectores transpuestos porque los autovectores se interpretan a nivel de columna
graficarVectores(autovectores.T, ["blue", "red"])

# pongamos en el mismo grafico la nube de puntos
plt.plot(xy_centrado[:,0], xy_centrado[:,1]/20, ".")

plt.show()
../_images/7875dd42df2ed28f4bf6cfe7022bbaa6412fd6a451f9c1d85f29d5936948abd4.png

Intuitivamente se puede pensar que el autovector que corresponde al autovalor que captura mayor varianza de los datos es el rojo. Vamos a comprobarlo:

print(autovalores)
[1.85050946e+00 6.28759594e+04]

El primer autovalor corresponde al vector azul, el segundo autovalor corresponde al vector rojo

Entonces se concluye que la columna que corresponde al segundo autovalor, es la que captura la mayor varianza de los datos.

Calculando los componentes principales#

xy_nuevo = autovectores.T.dot(xy_centrado.T)
# pongamos en el mismo grafico la nube de puntos
plt.plot(xy_nuevo[0, :], xy_nuevo[1, :], ".")

plt.show()
../_images/ce732bd209c30c5ab9ecf794af31888a8f303aff981d1758aabf8a21f7653571.png

En este punto, si quisieramos, podriamos quedarnos con la variable Y, que es la que esta capturando la mayor parte de la varianza

Created in deepnote.com Created in Deepnote