Equivale a una transformación lineal ya que aplica sobre un vector siguiendo las reglas de linealidad y da como resultado otro vector en otro espacio vectorial
Para el caso de la matriz diagonal el efecto es un reescalamiento del vector y en el caso de una matriz ortogonal el efecto es una rotación y luego una reflexión
Es la factorización del tipo $$ A = U\ \Sigma T^T $$ Donde una matriz se puede expresar como multiplicación de una matriz ortogonal U por una matriz diagonal y finalmente por otra matriz ortogonal.
Diagonalizar una matriz es encontrar una matriz tal que se cumpla
$$ A = P D P^{-1} $$donde P es invertible y cuyos vectores columna son los eigenvectores de A
Los eigenvectores representan la dirección de la transformación sobre un vector
Como la aplicación de una rotación $(U)$ luego un reescalamiento $(\Sigma)$ y finalmente otra rotación $(T^T)$
La diagonalización es un caso especial de SVD pero que solo es aplicable a matrices cuadradas
Conociendo la SVD de una matriz, hay algunos valores de $\sigma $ que son significativos otros son extremadamente pequeños, esto es podemos expresar a la matriz A como $$ A = U\Sigma V^T = \sum_{i=1}^{r} u_i\sigma_i v_i^T $$
Cualquier matriz es la suma de r matrices de rango 1
Se debe considerar un punto inicial posteriormente se escoge una dirección de descenso $d^k = -\nabla f(x^k)$, se realiza de manera iterativa $x^{k+1} = x^k + \alpha_k d^k $ hasta que el método converge
In [6]:
%matplotlib inline
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
def readImage(pathFile):
im = Image.open(pathFile)
im = im.convert('LA')
plt.figure(figsize=(6, 3))
plt.imshow(im,cmap='gray')
data = np.array(list(im.getdata(band=0)),int)
data.shape = (im.size[1], im.size[0])
data = np.matrix(data)
return data
def SVD(data,k):
U, s, V = np.linalg.svd(data)
plt.imshow(np.matrix(U[:, :k]) * np.diag(s[:k]) * np.matrix(V[:k, :]), cmap='gray')
titulo = "Imagen con k = %s" % k
plt.title(titulo)
plt.show()
Recibir el path de un archivo de imagen
In [7]:
imagen = readImage("baboon_256.png")
Realizar y verificar la descomposición svd
In [9]:
U, s, V = np.linalg.svd(imagen)
In [10]:
U
Out[10]:
In [15]:
imagenSVD = np.dot(np.dot(U,np.diag(s)),V)
Comprobando
In [16]:
np.allclose(imagenSVD,imagen)
Out[16]:
Usar la descomposición para dar una aproximación de grado k de la imagen
Para un grado 20, tenemos que
In [17]:
SVD(readImage("baboon_256.png"), 20)
Eligiendo distintos valores de k
In [18]:
for k in range(1,50,10):
SVD(readImage("baboon_256.png"),k)
¿Qué tiene que ver este proyecto con compresión de imágenes?
Existe un valor de k para el cual la imagen se puede visualizar de manera similar al original considerando menos valores de la matriz que utiliza para su representación, esto puede ser utilizado en la compresión de imágenes.
Programar una función que dada cualquier matriz devuelva la pseudainversa usando la descomposición SVD.
In [19]:
def pInverse(A):
U,d,V = np.linalg.svd(A)
ddiag = np.diag(d)
for i in range(0,max(ddiag.shape)):
if ddiag[i,i]!=0:
ddiag[i,i] = 1/ddiag[i,i]
return np.dot(np.dot(np.transpose(V),ddiag),np.transpose(U))
def solve(A,b):
return np.dot(pInverse(A),b)
Jugar con el sistema Ax=b donde A=[[1,1],[0,0]] y b puede tomar distintos valores
In [24]:
A= np.array([[1,1],[0,0]])
b = np.array([[1],[1]])
x = solve(A,b)
In [25]:
print(x)
In [26]:
b = np.array([[2],[2]])
In [27]:
x = solve(A,b)
In [28]:
print(x)
In [29]:
b = np.array([[-2],[2]])
In [30]:
print(solve(A,b))
La solución no es única y es del tipo $$x_1 = x_2$$
Repetir cambiando A=[[1,1],[0,1e-32]]
In [38]:
A= np.array([[1,1],[0,1e-32]])
b = np.array([[1],[1]])
x = solve(A,b)
In [39]:
print(x)
In [40]:
b = np.array([[2],[-2]])
In [41]:
x = solve(A,b)
In [37]:
print(x)
La solución no es única, pero difiere del caso anterior de que ahora es de la forma $$x_1 = -x_2$$
Deben programar un script que lea el archivo study_vs_sat.csv y lo almacene como un data frame de pandas.
In [42]:
import pandas as pd
In [44]:
df=pd.read_csv('study_vs_sat.csv')
In [46]:
df
Out[46]:
In [50]:
df.plot.scatter(x='study_hours',y='sat_score')
Out[50]:
Pleantear como un problema de optimización que intente hacer una aproximación de la forma sat_score ~ alpha + beta*study_hours
Haciendo sat_score = sat , y study_hours = shours, lo que se puede expresar como $$ sat = \alpha + \beta \ shours + \epsilon_1 $$ Por lo que se busca minimizar el error $$ \epsilon_i $$ $$ \sum_{i=1}^{n} {\epsilon_i}^2 = \sum_{i=1}^{n} {(sat_i - \alpha - \beta \ shours_i )}^2 $$ El gradiente es entonces $$ \frac{\partial}{\partial \alpha} = -2 \sum_{i=1}^{n} {(sat_i - \alpha - \beta \ shours_i )}$$ $$ \frac{\partial}{\partial \beta} = -2 \sum_{i=1}^{n} shours_i{(sat_i - \alpha - \beta \ shours_i )}$$
Programar una función que reciba valores de alpha, beta y el vector sat_score y devuelva un vector array de numpy de predicciones
In [64]:
def predictions(alfa,beta,vector):
valfa = alfa * np.ones(vector.shape[0])
return valfa + np.dot(beta,vector)
In [69]:
predictions(5,100,np.array(df['study_hours']))
Out[69]:
Definan un numpy array X de dos columnas, la primera con unos en todas sus entradas y la segunda con la variable study_hours
In [95]:
sh = np.array(df['study_hours'])
sh.shape
X = np.ones((sh.shape[0], 2))
X[:,1] = sh
Calculen la pseudoinversa X^+ de X y computen (X^+)*sat_score para obtener alpha y beta soluciones.
In [99]:
Xinv = np.linalg.pinv(X)
In [100]:
sc = np.array(df['sat_score'])
In [103]:
b = np.dot(Xinv,sc)
In [104]:
b
Out[104]:
Comparen la solución anterior con la de la fórmula directa de solución exacta (alpha,beta)=(X^tX)^(-1)X^t*study_hours.
In [120]:
b_directo = np.dot(np.linalg.inv(np.dot(np.transpose(X),X)),np.dot(np.transpose(X),sc))
In [121]:
b_directo
Out[121]:
In [122]:
np.allclose(b,b_directo)
Out[122]:
In [140]:
plt.scatter(sh,sc)
plt.plot(sh, sh*b[1] + b[0],color="red")
plt.title("Compararción predicción vs valores reales")
plt.xlabel("study_hours")
plt.ylabel("sat_score")
plt.show()