Primera parte: Concimiento básico de Algebra Lineal

Pregunta 1:¿Por qué una matriz equivale a una transformación lineal entre espacios vectoriales?

Porque na matriz realiza las operaciones básicas de suma, resta y multiplicación sobre los vectores canonicos Al aplicar una matriz a un vector estoy obteniendo los cambios resultantes de estas operaciones sobre el vectr.

Pregunta 2:¿Cuál es el efecto de transformación lineal de una matriz diagonal y el de una matriz ortogonal?

Una matriz diagonal es un reescalamiento mientras que una ortogonal es una rotación.

Pregunta 3:¿Qué es la descomposición en valores singulares de una matriz?

La descomposición en valores singulares de una matriz es una aproximación a $A = U*D*V^{t}$ Donde: $U$ y $V$ son los valores singulares de $A$ y $D$ es una matriz diagonal.

Pregunta 4: ¿Qué es diagonalizar una matriz y que representan los eigenvectores?

La diagonalización de una matriz cuadrada $A_{m x m}$ es llevar el sistema de ecuaciones a la forma canonica, es decir encontrar sus eigenvectores. Los eigenvectores representan los valores propios de la ecuación.

Pregunta 5: Intuitivamente qué son los eigenvectores?

Los eigenvectores son la base ortogonal del espacio de la matriz. Ellos hacen las rotaciones y son reescalados por lambda.

Pregunta 6: Cómo interpretas la descomposición en valores singulares como una composición de tres tipos de transformaciones lineales simples?

La descomposición SVD lo que hace es rotar, reescalar y volver a rotar, siendo que en el caso de que la matriz A sea cuadrada, la segunda rotación llevará a la matriz a su posición original.

Pregunta 7: ¿Qué relación hay entre la descomposición en valores singulares y la diagonalización?

Los elementos $U,D,V$ ,resultantes de una descomposición en valores singulares, son los eigenvectores de la matriz A. Donde $D$ es una diagonalizacion.

Pregunta 8:¿Cómo se usa la descomposición en valores singulares para dar un aproximación de rango menor a una matriz?

En la descomposición $A = U*D*V^{t}$ , $D$ puede verse como una multiplicacion de matrices menores $\begin{bmatrix}D_{1} & 0\\0 & D_{2}\end{bmatrix}$ con el rango de D{1} y D{2} menor al rango de D. Entonces $A^{*}=U_{1}D_{1}V_{1}^{t}$ aquel que resuelve el problema de $ min ||A-A^{*}||$ s.a. $rank(A^{*})<rank(A)$

Pregunta 9: Describe el método de descenso gradiente

El metodo de optimización de la función $f(x)$ por descenso gradiente busca, de manera local: 1)encontrar los valores $x^{*}$ tal que $\nabla f(x^*)$ sea la dirección de mayor decenso(o asenso en caso de maximizar) 2)moverse en la dirección encontrada en un factor $\beta$ conocido como coeficiente de aprendizaje (o learning rate) de manera que $\hat{x}=x-\beta*\nabla f(x)$

Pregunta 10: Menciona dos problemas de optimizacion con restricciones y dos sin restricciones que te parezcan interesantes como científico de datos

Sin restricciones:

1) Maximizar el tiempo de uso de cierta aplicación móvil (un juego) y el life spam de esta. 2) Maximizar la probabilidad de encontrar vida en otros planetas.

Con restricciones

1) Mejorar el acceso a servicios públicos mejorando la planeación urbana. 2) Optimización de despliegue de paneles solares o molinos para energía eolica dada una superficie limitada y condiciones climatológicas


In [ ]:
# Segunda parte: Aplicaciones en Python

Se mostrará una aplicación de la SVD a la compresión de imágenes y reducción de ruido.


In [2]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import time

from PIL import Image

##Aquí abro la imagen y la convierto a gris
im = Image.open("/Users/usuario/Documents/MaestriaCD/Propedeutico/PropedeuticoDataScience2017/Tarea/Simpsons.png")
gris =im.convert("1")

plt.figure(figsize=(9, 6))



##convierto los datos de la imagen en una matriz con valores
mat_val = np.array(gris)


plt.title("Imagen Original")
plt.imshow(mat_val, cmap='gray');



In [4]:
###hago el SVD
U, D, V = np.linalg.svd(mat_val)

##Reconstruyo y grafíco la imagen de manera completa
img_rec = np.matrix(U) * np.diag(D) * np.matrix(V)

plt.title("Imagen reconstruida de manera completa")
plt.imshow(img_rec, cmap='gray');



In [5]:
##Escogiendo K=100 para reconstruir la imagen con solo K elementos del SVD
k=100

rec =np.matrix(U[:,:k]) *np.diag(D[:k])* np.matrix (V[:k,:])
plt.title("Imagen reconstruida con  100  valores")
plt.imshow(rec, cmap='gray')


Out[5]:
<matplotlib.image.AxesImage at 0x11bb9d358>

In [6]:
##Escogiendo K=150 para reconstruir la imagen con solo K elementos del SVD
k=150

rec =np.matrix(U[:,:k]) *np.diag(D[:k])* np.matrix (V[:k,:])
plt.title("Imagen reconstruida con  150  valores")
plt.imshow(rec, cmap='gray')


Out[6]:
<matplotlib.image.AxesImage at 0x11be002e8>

In [7]:
##Escogiendo K=200 para reconstruir la imagen con solo K elementos del SVD
k=200

rec =np.matrix(U[:,:k]) *np.diag(D[:k])* np.matrix (V[:k,:])
plt.title("Imagen reconstruida con  200  valores")
plt.imshow(rec, cmap='gray')


Out[7]:
<matplotlib.image.AxesImage at 0x11bffe7b8>

Pregunta: Qué tiene que ver este proyecto con compresión de imágenes?

Se puede utilizar la descomposición SVD con una aproximacion de grado K optima para guardar la imagen en un tamaño menor al original, pudiendo despues reconstruirla a partir de los elementos de SVD.

Pseudoinversa y sistemas de ecuaciones.

Hacer una función que me de la pseudoinversa de una matriz A


In [28]:
import numpy as np 

def pseudo (A):
    
    X =np.array(A)
    U, D, V = np.linalg.svd(X, full_matrices=False)
    
    V_t = np.transpose(V)
    U_t = np.transpose(U)
    D_diag=np.diag(D)
    rows, col =D_diag.shape
    D_inv = np.zeros((rows,col))
    
    ##Aquí calculo la inversa de D, invirtiendo los valores y poniendo 0 en vez de 1/0
    
    for i in range(0,max(rows,col)):
        if D_diag[i,i]!= 0 :
            D_inv[i,i]=1/D_diag[i,i]
        else :
            D_inv[i,i]= 0
            
    ##aquí reconstruyo la pseudoinversa de A
    pseudo = np.dot(np.dot(V_t, D_inv), U_t)
    
    return pseudo

Hacer una función que me resuelva un sistema de ecuaciones Ax=b


In [29]:
def solve (A,y):
    A= np.array(A)
    Y=np.array(y)
    
    ##  reviso el tamaño
    rows, col =A.shape
    vec_rows, vec_col = Y.shape   
    
    if rows != vec_rows:
        raise Exception ("El tamaño de la matriz y el vector no coinciden")
    else:
        inv=pseudo(A)
        solve= np.dot(inv, Y)
        
    return (solve)

In [19]:
A=[[1,1],[0,0]]
b=[[1],[1]]
solve(A,b)


Out[19]:
array([[ 0.5],
       [ 0.5]])

In [20]:
pseudo(A)


Out[20]:
array([[ 0.5,  0. ],
       [ 0.5,  0. ]])

A es una matriz es que representa al sistema de ecuaciones $ X_{1}+X_{2}=b_{1}$ y $b_{2}=0$, su imagen es $b = \begin{bmatrix}b_{1}\\0 \end{bmatrix}$. La solución no es única ya que hay una variable libre. Dada la forma de la pseudoinversa de A $\begin{bmatrix}.5 & 0\\.5 & 0 \end{bmatrix}$ la función siempre regresará una respuesta $\begin{bmatrix}x_{1}=b_{1}/2\\x_{2}=b_{2}/2 \end{bmatrix}$ aunque $b_{2} != 0$


In [ ]:


In [ ]:


In [24]:
import math
A=[[1,1],[0,1*math.exp(-32)]]

print(pseudo(A))


[[  1.00000000e+00  -7.89629602e+13]
 [  0.00000000e+00   7.89629602e+13]]

In [25]:
solve(A,b)


Out[25]:
array([[ -7.89629602e+13],
       [  7.89629602e+13]])

En este caso la matriz tiene una solución única ya que $b_{2}=exp-32$ y las x´s son diferentes a las del caso anterior.

OLS


In [23]:
##Programando un script para descargar el archivo .csv de Github y convertirlo en un data frame

import numpy as np
import pandas as pd
import statsmodels.formula.api as sm
import matplotlib.pyplot as plt


#Script para descargar archivo y convertirlo en Data Frame con Pandas

#url="/Users/usuario/Documents/MaestriaCD/Propedeutico/PropedeuticoDataScience2017/study_vs_sat.csv"
url="https://raw.githubusercontent.com/mauriciogtec/PropedeuticoDataScience2017/master/Tarea/study_vs_sat.csv"
data = pd.read_csv(url)

data=pd.read_csv(url)
data= pd.DataFrame(data)

Al hacer una aproximación de la forma $sat_score= \alpha + \beta*study_hours + \epsilon$ podemos plantear la minimización de errores al cuadrado de tal manera que $$min \epsilon^{2} = min_{\alpha,\hat{\beta}} satscore - \alpha-\hat{\beta}*study hours$$ $$min_{\alpha,\hat{\beta}} y - X\hat{\beta}$$ En este caso $\alpha$ y $\beta$ resultantes de las condiciones de primer orden del problema de minimización son los gradientes que estamos buscando


In [24]:
##Deefine una función que me de una predicción para cada valor de sat_score
##

def prediction (S,alpha,beta):
    
    prediction=np.zeros(len(data))
    
    for i in range(len(data)):
        score=S[i]
        prediction[i]=alpha+beta*score
      
    return prediction

In [25]:
##puedo usar datos que se me ocurran

alpha=-353.164879499
beta= 25.3264677779 
S=data["study_hours"]


##Entonces usando esta información puedo hacer la predicción usando mi función

score_pred=prediction(S,alpha,beta)
print(score_pred)


[-251.85900839 -125.2266695   -99.90020172    1.40566939 -251.85900839
 -175.87960505  -49.24726616  204.01741161 -327.83841172 -277.18547617
 -150.55313728  -74.57373394 -226.53254061 -201.20607283  -99.90020172
  -74.57373394   52.05860495  -23.92079839  -23.92079839  -99.90020172]

In [26]:
##Definiendo el numpy array con 1 en el primer vector
##y sat_score en el segundo

Origen= data['Origen'] = np.ones(( len(data), ))
X=data[["Origen","study_hours"]]
print(X)


    Origen  study_hours
0      1.0            4
1      1.0            9
2      1.0           10
3      1.0           14
4      1.0            4
5      1.0            7
6      1.0           12
7      1.0           22
8      1.0            1
9      1.0            3
10     1.0            8
11     1.0           11
12     1.0            5
13     1.0            6
14     1.0           10
15     1.0           11
16     1.0           16
17     1.0           13
18     1.0           13
19     1.0           10

In [30]:
###Calculando X^+ * study_hours para obtener la alpha y beta
X_inv=pseudo(X)
alpha_aprox,beta_aprox=np.dot(X_inv,data["sat_score"])
print(alpha_aprox, beta_aprox)


353.164879499 25.3264677779

In [32]:
##ahora, haciendo la formula de estimadores de OLS de veras para calcular alpha t beta
X_t=np.transpose(X)
Sxx=np.dot(X_t,X)
Sxy=np.dot(X_t,data["sat_score"])
Sxx_inv= pseudo(Sxx)

alpha,beta= np.dot(Sxx_inv,Sxy)

print(alpha,beta)


353.164879499 25.3264677779

In [33]:
##visualizando los datos correctos vs las aproximaciones

alpha=353.164879499
beta= 25.3264677779 
S=data["study_hours"]

prediccion=prediction(S, alpha,beta)


colors = ['red',  'blue']

pred=plt.plot(prediccion, 'bo', markersize=10)  # blue circle with size 10 
val=plt.plot(data["sat_score"], 'ro', ms=10,)
plt.legend((pred, val),
           ('Valores de la predicción',"Valor Real"),
           scatterpoints=1,
           loc='lower left',
           ncol=3,
           fontsize=8)

plt.show()


/Users/usuario/anaconda/lib/python3.6/site-packages/matplotlib/legend.py:634: UserWarning: Legend does not support [<matplotlib.lines.Line2D object at 0x11abf4400>] instances.
A proxy artist may be used instead.
See: http://matplotlib.org/users/legend_guide.html#using-proxy-artist
  "#using-proxy-artist".format(orig_handle)
/Users/usuario/anaconda/lib/python3.6/site-packages/matplotlib/legend.py:634: UserWarning: Legend does not support [<matplotlib.lines.Line2D object at 0x1183ed780>] instances.
A proxy artist may be used instead.
See: http://matplotlib.org/users/legend_guide.html#using-proxy-artist
  "#using-proxy-artist".format(orig_handle)

In [ ]:


In [ ]: