Laboratorio 1 - Parte 2¶
Regresión logística
Recuerda que una vez abierto, Da clic en “Copiar en Drive”, de lo contrario no podras alamancenar tu progreso
Nota: no olvide ir ejecutando las celdas de código de arriba hacia abajo para que no tenga errores de importación de librerías o por falta de definición de variables.
#configuración del laboratorio
# Ejecuta esta celda!
%load_ext autoreload
%autoreload 2
!wget https://raw.githubusercontent.com/jdariasl/ML_2020/master/Labs/commons/utils/general.py -O general.py
from general import configure_lab1_p2
configure_lab1_p2()
from lab1 import *
GRADER, x, y = part_2()
Ejercicio 1: Contextualización del problema¶
En esta sesión de laboratorio, vamos a resolver un problema de clasificación. Los variables que vamos a usar ya se encuentran cargadas:
# tienes ya cargadas las siguientes variables:
print("conjunto de datos, muestra \n",x[range(10), :] )
print("")
print(" muestra de etiquetas a predecir \n", y[range(10)])
#Ejercicio de Codigo
def clases_muestras_carac(X, Y):
"""Esta funcion es encargada retornar el numero clases, muestras
y caracteristicas del conjunto de datos X y Y
X: matriz numpy con el conjunto de datos para entrenamiento
Y: matriz numpy con el conjunto de etiquetas
retorna:
numero de clases (int/float)
numero de muestras (int/float)
numero de caracteristicas (int/float)
"""
##Pista: es de utilidad el metodo np.unique ?
N,nf =
clases =
return (N,nf,clases)
## la funcion que prueba tu implementacion
GRADER.run_test("ejercicio1", clases_muestras_carac)
En los problemas de clasificación, que lo permiten, es de utilidad visualizar los datos. De esta manera uno puede determinar que modelos o algortimos pueden tener mejor rendimiento. En la siguiente función, debera, graficar los datos usando la función scatter de matplotlib.
#Ejercicio de Codigo
def scatter_plot(X, Y):
"""Esta funcion es encargada de graficar usando un scatter plot
un problema de clasificacion.
X: matriz numpy con el conjunto de datos para entrenamiento.
esta debera ser usada para los ejes del grafico. puede asumir
que solo va tener dos columnas
Y: matriz numpy con el conjunto de etiquetas. Debera se usada
para mostrar en diferentes colores, las etiquetas de cada una
de las muestras
retorna:
grafica matplotlib
"""
## puedes accerder con plt al funcion adecuacada
## Pista: recuerda como indexar matrices
## Pista: recuerda el uso de np.ravel
# para mostrar el grafico
figure = plt.gcf()
plt.show()
return (figure)
## la funcion que prueba tu implementacion
# ignora los graficos que se muestran
GRADER.run_test("ejercicio2", scatter_plot)
#@title Pregunta Abierta
#@markdown ¿El problema es linealmente separable? justifique su respuesta
respuesta_1 = "" #@param {type:"string"}
Ejercicio 2: entrenamiento¶
En este laboratorio se va a realizar un procedimiento análogo al laboratorio anterior, pero con el modelo de regresión logística que sirve para resolver problemas de clasificación (en principio biclase).
Analice los siguientes métodos a la luz de la teoría vista para el modelo de regresión logística:
función de activación (sigmoidal),
modelo de regresión logística (logistic_regression),
potencia del polinomio
el cálculo del error en clasificación (error_logistic)
el gradiente descendente.
Luego de recordar estos conceptos. Complete la función sigmoidal:
#Ejercicio de Código
def sigmoidal(z):
"""Función de activación Sigmoidal
z: es la varible a la que se le va aplicar el sigmoide.
es un array numpy de uan sola dimension
retorna: el valor del sigmiode
"""
#Complete la siguiente línea con el código para calcular la salida de la función sigmoidal
s =
return s
## la funcion que prueba tu implementacion
GRADER.run_test("ejercicio3", sigmoidal)
El la siguiente celda se sugiere la implementación, de los siguientes conceptos:
modelo de regresión logística (logistic_regression),
potencia del polinomio
el cálculo del error en clasificación (error_logistic)
comprenda que hacen estas funciones y ejecute la celda para cargar las funciones, para porder usarlas
def logistic_regression(X, W):
"""calcula la regresión logistica
X: los valores que corresponden a las caractersiticas
W: son los pesos usadados para realizar la regresión
retorna: valor estimado por la regresion
"""
#Con np.dot se realiza el producto matricial. Aquí X (extendida) tiene dim [Nxd] y W es dim [dx1]
Yest = np.dot(X,W)
Y_lest = sigmoidal(Yest)
#Se asignan los valores a 1 o 0 según el modelo de regresión logística definido
pos = 0
for tag in Y_lest:
if tag > 0.5:
Y_lest[pos] = 1
elif tag < 0.5:
Y_lest[pos] = 0
pos += 1
return Y_lest #Y estimado: Esta variable contiene ya tiene la salida de sigm(f(X,W))
def potenciaPolinomio(X,grado):
"""calcula la potencia del polinomio
X: los valores que corresponden a las caractersiticas
grado: esl grado para realizar la potencia al polinomio
retorna: el valor de X despues elevarlo al grado del polinimoo indicado
"""
X2 = X.copy()
if grado != 1:
for i in range(2,grado+1):
Xadd = X**i
X2 = np.concatenate((X2, Xadd), axis=1)
return X2
def error_logistic(Y_lest, Y):
"""calculo del error logistico
Si es diferente el Y_estimado con el Y_real cuenta como un error
Y_lest: numpy array con los valores de etiquetas estimadas
Y: numpy array valor con los valores reales de las etiquetas
retorna: error de clasificación -- numpy array
"""
error = 0
for ye, y in zip(Y_lest, Y):
if ye != y:
error += 1
error = error/np.size(Y)
return error
De igual manera, debemos extender nuestro conjunto de datos. Comprende que hace la siguiente celda de código y ejecutala. Muy importante ejecutar SOLA UNA vez.
#Aca llamamos la funcion creada anteriormente
# para obtener el numero muestras y caractersiticas
muestras,caracterisitcas,num_clases = clases_muestras_carac(x, y)
#Extendemos la matriz de X para el parámetro independiente
unos = np.array([np.ones(muestras)])
x = np.concatenate((unos.T, x), axis=1)
x = x.reshape(muestras, caracterisitcas+1)
y = y.reshape(np.size(y), 1)
recordando lo aprendido anteriormente, dividimos nuestro cojunto de datos y normalizamos.
#Dejamos algunas muestras para el proceso de entrenamiento y otras para evaluar qué tan bueno fue el aprendizaje del modelo
random.seed(1)
N = muestras
ind=np.random.permutation(N)
Xtrain = x[ind[0:int(math.ceil(0.7*N))],:]
Xtest = x[ind[int(math.ceil(0.7*N)):N],:]
Ytrain = y[ind[0:int(math.ceil(0.7*N))]]
Ytest = y[ind[int(math.ceil(0.7*N)):N]]
# normalizamos
Xtrain, Xtest = normalizar(Xtrain, Xtest)
Ahora vamos a completar el código de la regla de actualización de los parámetros del algoritmo de gradiente_descedente:
recordar que
Recuerda que debe usar las funciones ya implementadas y no usar ninguna otra libreria, adicional a las librerias ya pre-cargadas como numpy.
Adicionalmente, dentro de nuestra función, vamos incluir una transformación polinómica.
Nota: Para el problema de clasificación tenga presente que si ya implementó la regla de actualización de parámetros para el modelo de regresión polinomial múltiple, este punto es trivial, puesto que sólo tiene que incluir la función sigmoidal tal como lo vimos en la teoría.
#ejercicio de codigo
def gradiente_descendente_logistic_poly(X,Y,grado,eta, iteraciones):
"""Gradiente descendente para regresión lineal múltiple
X: Matriz de datos extendida
Y: vector con los valores a predecir
W: Vector de parámetros del modelo
eta: Taza de aprendizaje
grado: grado para usar en la transformacion polinomica
iteraciones: numero de iteraciones maxima
retorna: W el valor de de los parametros de regresión polinomica
"""
X2 = potenciaPolinomio(X,grado)
#Tomamos el número de variables del problema leugo de la transformacion
d = np.size(X2,1)
#Tomamos el número de muestras de la base de datos
N = np.size(X2,0)
#Inicializamos el vector de parámetros
W = np.zeros(d)
W = W.reshape(np.size(W),1)
for iter in range(iteraciones):
#Aquí debe completar el código con la regla de actualización de los parámetros W para regresión
#logística. Tenga en cuenta los nombres de las variables ya creadas: W, X, Y
Y_estimado = logistic_regression(X2,W)
W =
#Error en clasificación
Y_estimado = logistic_regression(X2,W)
error_clasificacion = error_logistic(Y_estimado,Y)
print("error despues de finalizar la iteraciones", error_clasificacion)
return W
## la funcion que prueba tu implementacion
GRADER.run_test("ejercicio4", gradiente_descendente_logistic_poly)
Finalmente se sugiere la siguiente funcion para evaluar el error del modelo. Entienda su funcionamiento.
def evaluar_modelo (W, X_to_test, Y_True, grado):
""" funcion que evalua un modelo de regresión usando el error cuadratico medio
W: es un matriz con los parametros del modelo entrenados
X_to_test: conjunto de datos para usar en el evaluamiento del modelo
Y_True: valores reales para usar en el evaluamiento del modelo
grado: valor del polinomio a usar
retorna: el de clasificación.
"""
X2 = potenciaPolinomio(X_to_test,grado)
Y_estimado = logistic_regression(X2,W)
error_clasificacion = error_logistic(Y_estimado,Y_True)
return(error_clasificacion)
Ejercicio 3: Experimentar¶
Con la función implementada vamos a entrenar un modelo y calcular su error de entrenamiento
w = gradiente_descendente_logistic_poly(Xtrain,Ytrain,1,0.0001, 1000)
error_test = evaluar_modelo(w, Xtest, Ytest, grado = 1)
print("error en el conjunto de pruebas", error_test)
En nuestro primer experimento vamos a evaluar el rendimiento del modelo usando varias tasas de aprendizaje y grados de polinimios. Vamos a dejar por ahora un numero de iteraciones fijas = 50. Para ello completa la siguiente función.
## ejercicio de codigo
def experimentar (Xtrain, Xtest, Ytrain, Ytest, tasas, grados):
""" funcion para realizar experimentos.
Xtrain: conjunto de datos
Xtest:
Ytrain:
Ytest:
tasas: Es una lista con los valores númericos de tasas de aprendizaje
para realizar los experimentos
grados: Es una lista con los valores númericos de grados
para realizar los experimentos
retorna: un dataframe con el resultados de los experimentos
"""
numero_iter = 50
resultados = pd.DataFrame()
idx = 0 # indice
for eta in tasas:
for grado in grados:
W =
error_entrenamiento =
error_prueba =
resultados.loc[idx,'grado'] = grado
resultados.loc[idx,'tasa de aprendizaje'] = eta
resultados.loc[idx,'error_entreamiento'] = error_entrenamiento
resultados.loc[idx,'error_prueba'] = error_prueba
idx = idx+1
return (resultados)
## la funcion que prueba tu implementacion
GRADER.run_test("ejercicio5", experimentar)
tasas = [1,0.1,0.001]
grados = [1,2,3,4,5]
resultados = experimentar (Xtrain, Xtest, Ytrain, Ytest, tasas, grados)
# para ver los resultados
resultados
#@title Pregunta Abierta
#@markdown ¿con base a los resultados anteriores, qué efecto tiene el grado en los errores de entrenamiento y de prueba? justifique
respuesta_2 = "" #@param {type:"string"}
#@title Pregunta Abierta
#@markdown ¿es normal que los errores de entrenamiento y prueba sean diferentes? justifique
respuesta_3 = "" #@param {type:"string"}
En los problemas de clasificación, es muy importante entender el numero de muestras que el modelo clasifico mal. Esto es necesario observarlo tanto en entrenamiento como en pruebas. Vamos crear una función para esto.
#ejercicio de codigo
def numero_de_errores (W, X, Y, grado):
"""función que cuenta los errores de un modelo de regresión logistica
W: vector con los parametros de un modelo de regresión logistica
previamente entrenado
X: conjunto de datos a usar (numpy matrix)
Y: conjunto con las etiquetas verdaderas. (numpy array)
grado: grado usado en el modelo de regresión logistica
retorna: numero de errores (int/float)
(es decir el numero de veces que la etiqueta predicha es diferente a la etiqueta real)
"""
X2 = potenciaPolinomio(X,grado)
Y_estimado = logistic_regression(X2,W)
numero_errores = np.sum(Y_estimado!=Y)
return numero_errores
## la funcion que prueba tu implementacion
GRADER.run_test("ejercicio6", numero_de_errores)
Ahora, use la función. Entrene nuevamente un modelo con los mejores parametros obtenidos y calcule cuantas muestras quedaron mal clasificadas. Tanto en el conjunto de entrenamiento y de prueba.
Si hay parametros empatados, el modelo que tenga menos parametros deberia ser el mejor.
# puedes usar el siguiente código para ordenar los resultados y ver los 3 primeros
# resultados, usa esta salida, para ver cuales fueron los mejores parámetros
resultados.sort_values(by = ['error_prueba', 'grado'], ascending = True).head(3)
W = gradiente_descendente_logistic_poly(Xtrain,Ytrain,grado = ,eta = , iteraciones = 50)
print("estos son los pesos para el modelo entrenando \n", W)
num_errores_entrenamiento = numero_de_errores (W, Xtrain, Ytrain, grado = 4)
num_errores_prueba = numero_de_errores (W, Xtest, Ytest, grado = 4)
print("muestras mal clasificadas en entrenamiento", num_errores_entrenamiento)
print("muestras mal clasificadas en pruebas", num_errores_prueba)
#@title Pregunta Abierta
#@markdown ¿por qué se uso el error de prueba para ordenar la tabla de resultados en lugar del error de entrenamiento?
respuesta_4 = "" #@param {type:"string"}
#@title Pregunta Abierta
#@markdown Escribe aqui el numero de muestras que quedaron mal clasificadas en el conjunto de entrenamiento y de pruebas. ¿como calificarias el modelo entrenado?
respuesta_5 = "" #@param {type:"string"}
#@title Pregunta Abierta
#@markdown Escriba el modelo completo con sus variables y coeficientes de f(**x**,**w**) con la mejor frontera de decisión que encontró. usa los valores del último W entrenado. Recuerda tener presente el grado del polinomio
respuesta_6 = "0.0x1 + 1.0x1**2 + 2.0x2 + 3.0x2**3" #@param {type:"string"}
GRADER.check_tests()
#@title Integrantes
codigo_integrante_1 ='' #@param {type:"string"}
codigo_integrante_2 = '' #@param {type:"string"}
esta linea de codigo va fallar, es de uso exclusivo del los profesores
GRADER.grade()