# Configuracion para recargar módulos y librerías 
%reload_ext autoreload
%autoreload 2

# Si quieren graficos dentro del ipython notebook, sacar comentario a linea siguiente.
#%matplotlib inline 

from IPython.core.display import HTML

HTML(open("style/mat281.css", "r").read())

from mat281_code.lab import greetings
alumno_1 = ("Sebastian Flores", "2004001-7")
alumno_2 = ("Maria Jose Vargas", "2004007-8")

HTML(greetings(alumno_1, alumno_2))

"""
Explanation: <header class="w3-container w3-teal">
<img src="images/utfsm.png" alt="" height="100px" align="left"/>
<img src="images/mat.png" alt="" height="100px" align="right"/>
</header>
<br/><br/><br/><br/><br/>
MAT281
Laboratorio Aplicaciones de la Matemática en la Ingeniería
Regresión Lineal
INSTRUCCIONES

Anoten su nombre y rol en la celda siguiente.
Desarrollen los problemas de manera secuencial.
Guarden constantemente con Ctr-S para evitar sorpresas.
Reemplacen en las celdas de código donde diga #FIX_ME por el código correspondiente.
Ejecuten cada celda de código utilizando Ctr-Enter
End of explanation
"""


# Generando los datos
import numpy as np

# Model
m = 1000 # Number of data examples
true_coefficients = np.array([27., 5.])
true_intercept = 1982.
n = len(true_coefficients) + 1

# Data
nx1, nx2 = 21, 26
x1, x2 = np.meshgrid(np.linspace(-1.,1.,nx1), np.linspace(80.,120.,nx2))
X = np.array([x1.flatten(), x2.flatten()]).T
Y = true_intercept + np.dot(X, true_coefficients)

# Measurement contamination
measurement_error = np.random.normal(size=Y.shape)

# Mesured data
Y = Y + 200 * measurement_error/measurement_error.max()

"""
Explanation: Observación
Este laboratorio utiliza la librería sklearn (oficialmente llamada scikit learn), puesto que buscamos aplicar la técnica de regresión lineal a datos tal como se haría en una aplicación real. 
El laboratorio consiste de 2 secciones:

Explicación de uso de regresión lineal en sklearn y análisis de residuos.
Aplicación a problema real.

1. Regresión Lineal con sklearn
Generemos un conjunt de datos sintéticos para aplicar regresión lineal, utilizando numpy y sklearn. El modelo será inicialmente muy simple, del tipo
$$ y = \theta_0 + \theta_1 \ x_1  + \theta_2 x_2 + \varepsilon $$
con $x_i$, $\theta_i$ e $y$ valores reales, y $\varepsilon$ el error de medición.
End of explanation
"""


# Visualización de los datos
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Plot of data
fig = plt.figure(figsize=(16,8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:,0], X[:,1], Y, 'rs')
plt.xlabel("X[:,0]")
plt.ylabel("X[:,1]")
plt.title("y")
plt.show()

"""
Explanation: Visualicemos los datos que hemos generado.
End of explanation
"""


# Aplicando regresion lineal con sklearn a los datos
from sklearn import linear_model

regr = linear_model.LinearRegression(fit_intercept=True, normalize=False)
regr.fit(X, Y) # No es necesario agregar la columna de 1s, el algooritmo lo hace por nosotros. 
print "Intercepto hallado: ", regr.intercept_
print "Coeficientes hallados: ", regr.coef_
Y_pred = regr.predict(X) # Puedo verificar que valores daría el modelo en los puntos conocidos.

"""
Explanation: Apliquemos un modelo de regresión lineal, obteniendo el intercepto y coeficientes. Utilizando sklearn podemos obtener además la predicción bajo el modelo lineal de manera extremadamente sencilla.
End of explanation
"""


from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Plot of data
fig = plt.figure(figsize=(16,8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:,0], X[:,1], Y, 'rs')
ax.plot_trisurf(X[:,0], X[:,1], Y_pred, color="r", alpha=0.5, lw=0)
plt.xlabel("X[:,0]")
plt.ylabel("X[:,1]")
plt.title("y")
plt.show()

"""
Explanation: Visualicemos simultáneamente los datos y la superficie generada con la regresión lineal.
End of explanation
"""


# Analisando gráfico de los residuos
res = Y_pred - Y
plt.figure(figsize=(16,8))
plt.hist(res)
plt.show()

"""
Explanation: Hmm, se ve bastante bien. ¿Qué tal los residuos? ¿Responden a nuestra hipótesis de distribución normal? Realicemos una exploración visual.
End of explanation
"""


# Analisis estadístico de residuos
import scipy.stats as stats
z, pval = stats.normaltest(res)
if pval < 0.05:
    print "Not normal distribution"
print "p-value =", pval

"""
Explanation: El gráfico anterior parece suficientemente normal. Utilicemos un test de normalidad para verificar que efectivamente los residuos tengan una distribución normal.
End of explanation
"""


print "Error promedio en norma 1:\t", np.linalg.norm(res,1)/len(res)
print "Error promedio en norma 2:\t", np.linalg.norm(res,2)/len(res)
print "Error promedio en norma inf:\t", np.linalg.norm(res,np.inf)

"""
Explanation: Calculemos el error promedio en varias normas
End of explanation
"""


# 1.1 Desafio 
# Codigo para generar datos con otro tipo de error de medicion
# y para realizar regresión lineal y análisis de los datos.



"""
Explanation: Desafío 1
[10%] Desafio 1.1
Utilice el código anterior para generar los mismos datos, pero esta vez no contamine los datos con errores gausianos, sino con elija utilizar un error de tipo gamma, uniforme o poisson (o bien, alguna otra de las posibles). Utilice alguno de los siguientes códigos:
Python
    gamma_measurement_error = np.random.gamma(1, size=Y.shape)
    uniform_measurement_error = np.random.uniform(size=Y.shape)-0.5
    weibull_measurement_error = np.random.weibull(1, size=Y.shape)
End of explanation
"""


%%bash
head data/auto-mpg.data.txt

"""
Explanation: Desafío 1: Continuación
[10%] 1.2 Indique el tipo de error introducido, y los valores obtenidos para el intercepto y los coeficientes.
FIX ME: COMENTARIO AQUI 
[10%]  1.3 ¿Cómo se comparan los valores anteriores a los valores reales (conocidos) y los valores obtenidos para error normal?
FIX ME: COMENTARIO AQUI 
[10%]  1.4 ¿Se logra reconocer que los residuos no corresponden a una distibución normal? ¿Cómo?
FIX ME: COMENTARIO AQUI 
[10%]  1.5 Compare  el error promedio (residuos) del modelo 1 (gausiano) con el modelo 2 (no gausiano), utilizando norma 1, norma 2 y norma infinito. ¿Que observa?
FIX ME: COMENTARIO AQUI 
Aplicación a datos reales
Un conjunto de datos bastante interesante es el Motor Dataset, que contiene características de 392 automobiles, entre los años 1970 y 1982.
<img src="images/delorean.jpg" alt="" width="600px" align="middle"/>
Este conjunto de datos tiene los siguientes valores:

Rendimiento en millas por galon, mpg (real).
Cilindros del motor, cylinders (entero positivo).
Displazamiento del motor en pulgadas cúbicas, displacement (real).
Caballos de fueza, horsepower (real).
Peso en libras, weight (real).
Tiempo de aceleración de 0 a 100 km/h, acceleration (real).
Año del modelo, model year (entero positivo).
Pais de origen, origin (entero positivo, categórico).
Nombre del Auto, car name (string, unico para cada dato).

Como ya es tradición, exploraremos los datos utilizando head (o tail, o cat).
End of explanation
"""


import numpy as np
# Lectura de datos
Y = np.loadtxt("data/auto-mpg.data.txt", delimiter=" ", usecols=(0,))
X = np.loadtxt("data/auto-mpg.data.txt", delimiter=" ", usecols=(2,3,4,5))

# Procesamiento de datos

"""
Explanation: Desafío 2
[10 %] Desafio 2.1
Realice una regresión lineal a los datos, buscando predecir el rendimiento (en mpg) utilizando como predictores: el desplazamiento, los caballos de fuerza, el peso y la aceleración, correspondientes a las columnas 2, 3, 4 y 5. Utilice el código provisto anteriormente para ajustar un modelo de regresión lineal, obtener los coeficientes del modelo, realizar predicciones y analice los residuos. 
No es necesario incluir gráficos (pero tampoco está prohibido).
End of explanation
"""


# Calcular el mpg aqui
mpg = 0
print mpg

"""
Explanation: Desafío 2 : Continuación
2.2 [10%] ¿Qué valores se obtienen para el intercepto y los coeficientes de los datos?
FIX ME: COMENTARIO AQUI 
2.3 [10%] ¿Cuál es el error de entrenamiento en las distintas normas?
FIX ME: COMENTARIO AQUI 
2.4 [10%] ¿Qué tipo de residuo se obtienen? ¿Son gaussianos?
FIX ME: COMENTARIO AQUI 
Calculo el rendimiento en mpg tendría el Delorean, si en base a cierta información sabemos que posee: 

6 cilindros
174 pulgadas cúbicas desplazamiento. 
200 Caballos de fuerza.
2712 libras de peso.
Una aceleración de 10.5.
Se construyó el año 1981.

Consejo: Utilice el metodo .predict() apropiadamente.
End of explanation
"""


