Alumnos y Padrón
Cargamos las bibliotecas que se van a estar usando a lo largo de este notebook.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from preprocessing import prepararSetDeDatos
from preprocessing import prepararSetDeValidacion
from preprocessing import prepararSetDeHoldout
from preprocessing import expansionDelDataset
from preprocessing import conversionAVariablesNormalizadas
from funcionesAuxiliares import mostrarAUCScore
from funcionesAuxiliares import mostrarROCCurve
from funcionesAuxiliares import mostrarMatrizDeConfusion
from funcionesAuxiliares import escribirPrediccionesAArchivo
from funcionesAuxiliares import obtenerDatasets
from funcionesAuxiliares import obtenerHoldout
X, y = obtenerDatasets()
X = prepararSetDeDatos(X)
y = prepararSetDeValidacion(y)
def obtenerMejoresHiperparametros(datosPreprocesados):
mejor_distancia = None
mejor_metrica = None
mejor_valor = 0
mejor_k = None
y_array=np.array(y)
for distancia in ['uniform', 'distance']:
for metrica in ['minkowski','cosine','chebyshev','correlation']:
for k in [2,3,4,5,6,7,8,9,10,15,20,25,30]:
kf = StratifiedKFold(n_splits=8)
metricas = []
for fold_idx, (train_index, test_index) in enumerate(kf.split(datosPreprocesados, y_array)):
knn = KNeighborsClassifier(n_neighbors = k, weights = distancia, metric = metrica, n_jobs = -1)
knn.fit(datosPreprocesados[train_index], y_array[train_index].ravel())
predicciones = knn.predict_proba(datosPreprocesados[test_index])[:, 1]
score_obtenida = roc_auc_score(y_array[test_index],predicciones)
metricas.append(score_obtenida)
if np.mean(metricas) >= mejor_valor:
mejor_valor = np.mean(metricas)
mejor_k = k
mejor_distancia = distancia
mejor_metrica = metrica
return mejor_valor, mejor_k, mejor_distancia, mejor_metrica
KNN es un método de aprendizaje supervisado que consiste en predecir la clase de una instancia en base a sus vecinos.
Antes de comenzar a realizar predicciones, tenemos que tener en cuenta varias cuestiones. Estas son: qué clase de preprocesamiento necesita este metodo, y cuáles son los hiperparámetros que debemos de buscar para obtener mejores resultados.
Para el procesamiento de los datos, decidimos primero realizar la conversión a variables categóricas mediante OneHotEncoding de las variables detectadas en la primera parte del trabajo. También se le aplica a los datos en este método una normalización, de forma tal de que algún feature no tenga demasiado peso, cosa que puede afectar a las distancias al momento de calcularlas.
X_knn = conversionAVariablesNormalizadas(X)
Para la búsqueda de los hiperparámetros, consideramos que los mas relevantes son los siguientes:
K: Determina la cantidad de vecinos para una instancia. Comenzamos evaluando con cantidades bajas y lo vamos aumentando hasta tener una cantidad mayor.
El peso: Este es el peso que se le da a las distancias entre los puntos. Analizamos con 'uniform' (Todas las distancias valen lo mismo), y con 'distance' (Pesa a los puntos con la inversa de la distancia, mientras mas cerca, mas valor tenes).
Metrica: Es la forma en que se va a calcular la distancia. Se eligieron varias de forma aleatoria de la lista que tiene sklearn.
mejor_valor, mejor_k, mejor_distancia, mejor_metrica = obtenerMejoresHiperparametros(X_knn)
Observamos los valores obtenidos y procedemos a realizar el modelo definitivo de KNN con estos hiperparámetros.
print(mejor_valor.round(3))
print(mejor_k)
print(mejor_distancia)
print(mejor_metrica)
Ahora buscamos ver qué podemos obener aplicando otro preprocesado en este modelo. Para ello probamos con el preprocesado que expande el dataset categorizando valores numéricos y agrupando otros en clusters.
X_expandido = expansionDelDataset(X)
Mostramos cómo es el dataframe resultante de la expansión y buscamos los mejores hiperparámetros en este caso. Si obtenemos un mejor resultado usaremos este preprocesamiento para el modelo final de KNN.
X_expandido.head()
columnas_codificables_extra = ['pago_categorizado','edades_estratificadas','categoria_invitados']
columnas_numericas_extra = ['2_clusters','4_clusters','10_clusters','cantidad_total_invitados','total_pagado']
X_knn_expandido = conversionAVariablesNormalizadas(X_expandido,columnas_codificables_extra,columnas_numericas_extra)
mejor_valor_exp, mejor_k_exp, mejor_distancia_exp, mejor_metrica_exp = obtenerMejoresHiperparametros(X_knn_expandido)
print(mejor_valor_exp.round(3))
print(mejor_k_exp)
print(mejor_distancia_exp)
print(mejor_metrica_exp)
Obtenemos un promedio peor para el mejor valor de AUC-ROC al utilizar todas las columnas nuevas generadas.
Probamos ahora construir un modelo de KNN que no utilice todas las nuevas columnas que tiene el dataset expandido sino sólo un subconjunto de ellas.
columnas_codificables_extra = ['edades_estratificadas','categoria_invitados']
columnas_numericas_extra = ['2_clusters','4_clusters','10_clusters']
X_knn_expandido = conversionAVariablesNormalizadas(X_expandido,columnas_codificables_extra,columnas_numericas_extra)
mejor_valor_exp, mejor_k_exp, mejor_distancia_exp, mejor_metrica_exp = obtenerMejoresHiperparametros(X_knn_expandido)
print(mejor_valor_exp.round(3))
print(mejor_k_exp)
print(mejor_distancia_exp)
print(mejor_metrica_exp)
Vemos que mejoró levemente pero aún así no supero el preprocesamiento sin la información extra.
Entrenamos ahora un modelo definitivo con los primeros hiperparámetros que se encontraron al utilizar el dataset sin expandir para entrenar al modelo.
knn = KNeighborsClassifier(n_neighbors = mejor_k, weights = mejor_distancia, metric = mejor_metrica)
X_train, X_test, y_train, y_test = train_test_split(X_knn, y, test_size=0.25, random_state=0)
knn.fit(X_train, y_train)
Relizamos la predicción sobre los datos de evaluación, y evaluamos las métricas del modelo.
y_pred = knn.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['No vuelve','Vuelve']))
mostrarMatrizDeConfusion(y_pred,y_test)
Graficamos ahora la curva ROC.
mostrarROCCurve(knn,"KNN",X_test, X_train, y_test, y_train)
mostrarAUCScore(knn,"KNN",X_test,y_test)
Podemos observar que KNN tuvo un rendimiento bueno considerando que es un método relativamente sencillo.
Obtenemos y preparamos el nuevo archivo realizando el mismo preprocesamiento realizado anteriormente.
holdout = obtenerHoldout()
ids_usuarios = np.array(holdout['id_usuario'])
holdout = prepararSetDeHoldout(holdout)
holdout_knn = conversionAVariablesNormalizadas(holdout)
Finalmente, realizamos las predicciones y escribimos al archivo en el formato CSV pedido.
predicciones_holdout = knn.predict(holdout_knn)
escribirPrediccionesAArchivo(predicciones_holdout,"KNN",ids_usuarios)