Trabajo Práctico 2: Análisis con Naive Bayes - Organización de Datos

Configuraciones iniciales

Cargamos las bibliotecas correspondientes a este modelo.

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
In [2]:
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.model_selection import GridSearchCV
In [3]:
from sklearn.naive_bayes import MultinomialNB
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import CategoricalNB
In [4]:
from preprocessing import prepararSetDeDatos
from preprocessing import prepararSetDeHoldout
from preprocessing import prepararSetDeValidacion
from preprocessing import conversionAVariablesCodificadas
from preprocessing import conversionAVariablesContinuas
from preprocessing import expansionDelDataset
In [5]:
from funcionesAuxiliares import mostrarAUCScore
from funcionesAuxiliares import mostrarROCCurve
from funcionesAuxiliares import mostrarMatrizDeConfusion
from funcionesAuxiliares import escribirPrediccionesAArchivo
from funcionesAuxiliares import obtenerDatasets
from funcionesAuxiliares import obtenerHoldout

Carga y preparación del set de datos

Cargamos ambos set de datos, y se los pasamos a la funciones que realizan el armado hecho para el TP1.

In [6]:
X,y = obtenerDatasets()

X = prepararSetDeDatos(X)
y = prepararSetDeValidacion(y)

Funciones auxiliares

In [7]:
def obtenerMejorAlpha(modelo,datosPreprocesados):
    mejor_valor = 0
    mejor_alpha = None
    y_array=np.array(y)
    for valor_alpha in [0.001,0.01,0.1,0.3,0.5,0.7,1,2,3,10]:
        kf = StratifiedKFold(n_splits=2)
        metricas = []
        for fold_idx, (train_index, test_index) in enumerate(kf.split(datosPreprocesados, y_array)):
            modeloNB = modelo(alpha=valor_alpha)
            modeloNB.fit(datosPreprocesados[train_index], y_array[train_index].ravel())
            predicciones = modeloNB.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_alpha = valor_alpha
            
    return mejor_valor, mejor_alpha
In [8]:
def obtenerMejorHiperparametroGaussianNB(datosPreprocesados):
    mejor_valor = 0
    mejor_smoothing = None
    y_array=np.array(y)
    for valor_smoothing in [0.00000001,0.0000001,0.000001,0.00001,0.0001,0.001]:
        kf = StratifiedKFold(n_splits=8)
        metricas = []
        for fold_idx, (train_index, test_index) in enumerate(kf.split(datosPreprocesados, y_array)):
            modeloNB = GaussianNB(var_smoothing=valor_smoothing)
            modeloNB.fit(datosPreprocesados[train_index], y_array[train_index].ravel())
            predicciones = modeloNB.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_smoothing = valor_smoothing
            
    return mejor_valor, mejor_smoothing
In [9]:
def graficarAUCROC(tipo,modeloNB,X_test,X_train,y_test,y_train):
    
    fpr_nb_test,tpr_nb_test,thresholds_nb_test = roc_curve(y_test,modeloNB.predict_proba(X_test)[:,1])
    fpr_nb_train,tpr_nb_train,thresholds_nb_train = roc_curve(y_train,modeloNB.predict_proba(X_train)[:,1])

    zero_test = np.argmin(np.abs(thresholds_nb_test))
    zero_train = np.argmin(np.abs(thresholds_nb_train))

    plt.plot(fpr_nb_train,tpr_nb_train,label="ROC Curve "+tipo+" NB Train")
    plt.plot(fpr_nb_test,tpr_nb_test,label="ROC Curve  "+tipo+" NB Test")
    plt.xlabel("FPR")
    plt.ylabel("TPR")
    plt.plot(fpr_nb_test[zero_test],tpr_nb_test[zero_test],'o',markersize=10,label="threshold zero test",fillstyle="none",c="k",mew=2)
    plt.plot(fpr_nb_train[zero_train],tpr_nb_train[zero_train],'x',markersize=10,label="threshold zero train",fillstyle="none",c="k",mew=2)

    plt.legend(loc=4)
    plt.show()

CategoricalNB

Este modelo es utilizado para problemas de clasificación en los que se tienen variables categóricas.

Empezamos realizando el preprocesamiento a los datos. En este caso consiste en deshacernos de las variables con datos numéricos (ej. precio, edad) y codificar ordinalmente el resto de las variables. Probamos primero quedandonos con todas las categoricas.

In [10]:
X.head()
Out[10]:
sufijo tipo_de_sala genero edad amigos parientes precio_ticket fila nombre_sede autocompletamos_edad
0 Señor 4d hombre 73.0 0 0 1 No responde fiumark_quilmes False
1 Señora 4d mujer 35.0 1 1 2 No responde fiumark_quilmes False
2 Señor normal hombre 32.0 0 0 3 No responde fiumark_chacarita True
3 Señor 4d hombre 32.0 0 0 1 No responde fiumark_palermo True
4 Señorita 4d mujer 4.0 1 1 2 No responde fiumark_palermo False
In [11]:
columnasCategoricas = ['sufijo','tipo_de_sala','genero','fila','nombre_sede']
In [12]:
X_categoricalNB = conversionAVariablesCodificadas(X,columnasCategoricas)

Búsqueda de hiperparámetros

En cuanto a hiperparámetros, los modelos de Naive Bayes son simples, ya que solamente tienen un solo hiperparámetro importante, siendo este el alpha. El alpha indica cuanto smoothing se le va a estar aplicando a las diferentes combinaciones, de forma tal de no tener casos con probabilidad 0.

Preprocesamiento basico

Probamos primero con el preprocesamiento basico aplicado al preparar el set de datos.

In [13]:
mejor_valor, mejor_alpha = obtenerMejorAlpha(CategoricalNB,X_categoricalNB) 
In [14]:
print(f"El mejor valor de AUC fue: {round(mejor_valor,3)}")
print(f"El mejor alpha obtenido fue: {mejor_alpha}")
El mejor valor de AUC fue: 0.844
El mejor alpha obtenido fue: 3

Preprocesamiento expandido

Ahora veamos que aparece con el preprocesamiento que expande el dataset creando nuevas columnas.

In [15]:
X = expansionDelDataset(X)
In [16]:
X.head()
Out[16]:
sufijo tipo_de_sala genero edad amigos parientes precio_ticket fila nombre_sede autocompletamos_edad 2_clusters 4_clusters 10_clusters cantidad_total_invitados total_pagado pago_categorizado edades_estratificadas categoria_invitados
0 Señor 4d hombre 73.0 0 0 1 No responde fiumark_quilmes False 1 1 4 0 1 Pago poco mayor Fue solo
1 Señora 4d mujer 35.0 1 1 2 No responde fiumark_quilmes False 0 2 0 2 6 Pago normal adulto Fue en grupo
2 Señor normal hombre 32.0 0 0 3 No responde fiumark_chacarita True 0 2 0 0 3 Pago normal adulto Fue solo
3 Señor 4d hombre 32.0 0 0 1 No responde fiumark_palermo True 0 2 0 0 1 Pago poco adulto Fue solo
4 Señorita 4d mujer 4.0 1 1 2 No responde fiumark_palermo False 0 3 3 2 6 Pago normal ninio Fue en grupo
In [17]:
columnasCategoricas = ['sufijo','tipo_de_sala','genero','fila','nombre_sede','pago_categorizado','edades_estratificadas','categoria_invitados']
X_categoricalNB_exp = conversionAVariablesCodificadas(X,columnasCategoricas)
In [18]:
mejor_valor_exp, mejor_alpha_exp = obtenerMejorAlpha(CategoricalNB,X_categoricalNB_exp) 
In [19]:
print(f"El mejor valor de AUC fue: {round(mejor_valor_exp,3)}")
print(f"El mejor alpha obtenido fue: {mejor_alpha_exp}")
El mejor valor de AUC fue: 0.842
El mejor alpha obtenido fue: 10

Vemos que se obtuvo un valor similar al anterior.

Sacando algunas columnas

Probamos sacando las columnas de 'fila' y 'sede', ya que la primera esta en su mayoria compuesta por valores nulos ('No responde'), y la segunda no es un feature muy relevante para saber si alguien volveria o no.

In [20]:
columnasCategoricas = ['sufijo','tipo_de_sala','genero','pago_categorizado','edades_estratificadas','categoria_invitados']
X_categoricalNB_exp = conversionAVariablesCodificadas(X,columnasCategoricas)
In [21]:
mejor_valor_exp2, mejor_alpha_exp2 = obtenerMejorAlpha(CategoricalNB,X_categoricalNB_exp) 
In [22]:
print(f"El mejor valor de AUC fue: {round(mejor_valor_exp2,3)}")
print(f"El mejor alpha obtenido fue: {mejor_alpha_exp2}")
El mejor valor de AUC fue: 0.836
El mejor alpha obtenido fue: 10

Vemos que no se obtuvieron mejoras.

CategoricalNB con mejor hiperparámetro

Dividimos el set de datos y creamos el modelo con el valor de alpha obtenido.

In [23]:
X_train, X_test, y_train, y_test = train_test_split(X_categoricalNB, y, test_size=0.25, random_state=0)
In [24]:
categoricalNB = CategoricalNB(alpha=mejor_alpha)
In [25]:
categoricalNB.fit(X_train, y_train)
Out[25]:
CategoricalNB(alpha=3)

Realizamos ahora las predicciones correspondientes con la parte de entrenamiento y la de pruebas, una vez hecho eso, mostramos las métricas obtenidas para la parte de test.

In [26]:
y_pred = categoricalNB.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['No vuelve','Vuelve']))
              precision    recall  f1-score   support

   No vuelve       0.85      0.83      0.84       121
      Vuelve       0.75      0.78      0.76        80

    accuracy                           0.81       201
   macro avg       0.80      0.80      0.80       201
weighted avg       0.81      0.81      0.81       201

In [27]:
mostrarMatrizDeConfusion(y_pred,y_test)

Graficamos ahora la curva ROC para ambos casos.

In [28]:
graficarAUCROC("Categorical",categoricalNB,X_test,X_train,y_test,y_train)

Podemos observar que en este caso la curva de evaluación resulta mejor que la de entrenamiento, indicando que se generalizó mejor. Esto se debe a que se acerca mucho más hacia la esquina superior izquierda del gráfico. (Su área bajo la curva está más cerca de 1)

In [29]:
mostrarAUCScore(categoricalNB,"Categorical NB",X_test,y_test)
AUC para Categorical NB: 0.867

Ahora nos guardamos las probabilidades que predice este modelo, ya que las usaremos más adelante.

In [30]:
probabilidades_categorical = categoricalNB.predict_proba(X_train)
probabilidades_x_test_categorical = categoricalNB.predict_proba(X_test)

MultinomialNB

Procedemos de manera similar para Multinomial Naive Bayes. Este caso solamente difiere en que este modelo se utiliza para features discretos. Por lo que sacamos los atributos que no sirven para este caso y codificamos el resto. Probando los basicos al comienzo.

Preprocesamiento basico

In [31]:
X.head()
Out[31]:
sufijo tipo_de_sala genero edad amigos parientes precio_ticket fila nombre_sede autocompletamos_edad 2_clusters 4_clusters 10_clusters cantidad_total_invitados total_pagado pago_categorizado edades_estratificadas categoria_invitados
0 Señor 4d hombre 73.0 0 0 1 No responde fiumark_quilmes False 1 1 4 0 1 Pago poco mayor Fue solo
1 Señora 4d mujer 35.0 1 1 2 No responde fiumark_quilmes False 0 2 0 2 6 Pago normal adulto Fue en grupo
2 Señor normal hombre 32.0 0 0 3 No responde fiumark_chacarita True 0 2 0 0 3 Pago normal adulto Fue solo
3 Señor 4d hombre 32.0 0 0 1 No responde fiumark_palermo True 0 2 0 0 1 Pago poco adulto Fue solo
4 Señorita 4d mujer 4.0 1 1 2 No responde fiumark_palermo False 0 3 3 2 6 Pago normal ninio Fue en grupo
In [32]:
columnasDiscretas = ['sufijo','tipo_de_sala','genero','amigos','parientes','precio_ticket','fila','nombre_sede']
X_multinomialNB = conversionAVariablesCodificadas(X,columnasDiscretas)
In [33]:
mejor_valor, mejor_alpha = obtenerMejorAlpha(MultinomialNB,X_multinomialNB)
In [34]:
print(f"El mejor valor de AUC fue: {round(mejor_valor,3)}")
print(f"El mejor alpha obtenido fue: {mejor_alpha}")
El mejor valor de AUC fue: 0.815
El mejor alpha obtenido fue: 0.01

Preprocesamiento expandido

Habiendo obtenido el mejor alpha para el Multinomial Naive Bayes en el preprocesamiento basico, probamos ahora con el expandido.

In [35]:
columnasDiscretas = ['sufijo','tipo_de_sala','genero','amigos','parientes','fila','nombre_sede','precio_ticket','2_clusters','4_clusters','10_clusters',
                     'cantidad_total_invitados','pago_categorizado','edades_estratificadas','categoria_invitados']
X_multinomialNB_exp = conversionAVariablesCodificadas(X,columnasDiscretas)
In [36]:
mejor_valor_exp, mejor_alpha_exp = obtenerMejorAlpha(MultinomialNB,X_multinomialNB_exp)
In [37]:
print(f"El mejor valor de AUC fue: {round(mejor_valor_exp,3)}")
print(f"El mejor alpha obtenido fue: {mejor_alpha_exp}")
El mejor valor de AUC fue: 0.796
El mejor alpha obtenido fue: 0.01

Vemos que empeoro el promedio del AUC. Probamos sin algunas columnas.

Preprocesamiento con menos columnas

In [38]:
columnasDiscretas = ['sufijo','tipo_de_sala','genero','amigos','parientes','fila','precio_ticket',
                     'cantidad_total_invitados','pago_categorizado','edades_estratificadas','categoria_invitados']
X_multinomialNB_exp2 = conversionAVariablesCodificadas(X,columnasDiscretas)
In [39]:
mejor_valor_exp2, mejor_alpha_exp2 = obtenerMejorAlpha(MultinomialNB,X_multinomialNB_exp2)
In [40]:
print(f"El mejor valor de AUC fue: {round(mejor_valor_exp2,3)}")
print(f"El mejor alpha obtenido fue: {mejor_alpha_exp2}")
El mejor valor de AUC fue: 0.813
El mejor alpha obtenido fue: 0.3

Se observo una mejora respecto al primero sacando los resultados de los clusters y de la sede. Probamos un ultimo modelo con las caracteristicas que dieron mejor.

Multinomial NB con mejor combinacion

In [41]:
X_train, X_test, y_train, y_test = train_test_split(X_multinomialNB, y, test_size=0.25, random_state=0)
In [42]:
multinomialNB = MultinomialNB(alpha=mejor_alpha_exp2)
In [43]:
multinomialNB.fit(X_train, y_train)
Out[43]:
MultinomialNB(alpha=0.3)

Realizamos devuelta las predicciones de la parte de evaluación pero con este modelo.

In [44]:
y_pred = multinomialNB.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['No vuelve','Vuelve']))
              precision    recall  f1-score   support

   No vuelve       0.79      0.86      0.82       121
      Vuelve       0.75      0.65      0.70        80

    accuracy                           0.78       201
   macro avg       0.77      0.75      0.76       201
weighted avg       0.77      0.78      0.77       201

Como podemos observar, se obtuvieron en la mayoría de las métricas valores cercanos al 80% para ambas predicciones hechas. Vemos la matriz de confusión ahora y el área bajo la curva.

In [45]:
mostrarMatrizDeConfusion(y_pred,y_test)

Graficamos ahora la curva ROC para ambos casos.

In [46]:
graficarAUCROC("Multinomial",multinomialNB,X_test,X_train,y_test,y_train)

Observamos que devuelta la curva de evaluación tiene mejor forma que la de entrenamiento.

In [47]:
mostrarAUCScore(multinomialNB,"Multinomial NB",X_test,y_test)
AUC para Multinomial NB: 0.851

En este caso obtuvimos rendimientos bastante similares al del CategoricalNB, estando ligeramente abajo por unas milésimas.

In [48]:
probabilidades_multinomial = multinomialNB.predict_proba(X_train)
probabilidades_x_test_multinomial = multinomialNB.predict_proba(X_test)

GaussianNB

Utilizamos ahora Gaussian Naive Bayes. Este modelo es para features continuos, por lo que en su preprocesamiento nos quedaremos solamente con ese tipo de variables. Al realizar esto, no esperamos que este modelo tenga un gran rendimiento, ya que estaría considerando una parte reducida de los datos.

In [49]:
X_gaussianNB = conversionAVariablesContinuas(X)

Buscamos el hiperparámetro que tiene este modelo. (var_smoothing)

In [50]:
mejor_valor, mejor_var_smoothing = obtenerMejorHiperparametroGaussianNB(X_gaussianNB)
In [51]:
print(f"El mejor valor de AUC fue: {round(mejor_valor,3)}")
print(f"El mejor var_smoothing obtenido fue: {mejor_var_smoothing}")
El mejor valor de AUC fue: 0.652
El mejor var_smoothing obtenido fue: 0.001
In [52]:
X_train, X_test, y_train, y_test = train_test_split(X_gaussianNB, y, test_size=0.25, random_state=0)
In [53]:
gaussianNB = GaussianNB(var_smoothing = mejor_var_smoothing)
In [54]:
gaussianNB.fit(X_train, y_train)
Out[54]:
GaussianNB(var_smoothing=0.001)

Repetimos lo realizado anteriormente.

In [55]:
y_pred = gaussianNB.predict(X_test)
In [56]:
print(classification_report(y_test, y_pred, target_names=['No vuelve','Vuelve']))
              precision    recall  f1-score   support

   No vuelve       0.65      0.93      0.76       121
      Vuelve       0.69      0.25      0.37        80

    accuracy                           0.66       201
   macro avg       0.67      0.59      0.57       201
weighted avg       0.67      0.66      0.61       201

In [57]:
mostrarMatrizDeConfusion(y_pred,y_test)

Graficamos ahora la curva ROC para ambos casos.

In [58]:
graficarAUCROC("Gaussian",gaussianNB,X_test,X_train,y_test,y_train)

Notamos que en este caso se tuvo una curva mucho peor que en los anteriores casos.

In [59]:
mostrarAUCScore(gaussianNB,"Gaussian NB",X_test,y_test)
AUC para Gaussian NB: 0.657

Observamos que se obtuvo un valor muy bajo. Esto era esperable, ya que se están analizando muy pocas variables al considerar solamente las continuas.

In [60]:
probabilidades_gaussian = gaussianNB.predict_proba(X_train)
probabilidades_x_test_gaussian = gaussianNB.predict_proba(X_test)

"Ensamble" de Naive Bayes

Viendo que sklearn tiene la limitación que no permite trabajar a la vez con variables categóricas y variables continuas, decidimos realizar un ensamble al que le pasamos las probabilidades de los 3 modelos hechos anteriormente. De esta forma, logramos obtener un modelo de Naive Bayes que trabaje con ambos tipos de variables.

Comenzamos uniendo las probabilidades obtenidas anteriormente.

In [61]:
probabilidades_x_train = np.hstack((probabilidades_multinomial, probabilidades_categorical , probabilidades_gaussian))
probabilidades_x_test = np.hstack((probabilidades_x_test_multinomial, probabilidades_x_test_categorical , probabilidades_x_test_gaussian))
In [62]:
X_ensamble_gaussiano = np.vstack((probabilidades_x_train,probabilidades_x_test))
In [63]:
mejor_valor, mejor_var_smoothing = obtenerMejorHiperparametroGaussianNB(X_ensamble_gaussiano)
In [64]:
print(f"El mejor valor de AUC fue: {round(mejor_valor,3)}")
print(f"El mejor var_smoothing obtenido fue: {mejor_var_smoothing}")
El mejor valor de AUC fue: 0.484
El mejor var_smoothing obtenido fue: 1e-05
In [65]:
ensamble_gaussiano = GaussianNB(var_smoothing = mejor_var_smoothing)
In [66]:
ensamble_gaussiano.fit(probabilidades_x_train,y_train)
Out[66]:
GaussianNB(var_smoothing=1e-05)
In [67]:
y_pred = ensamble_gaussiano.predict(probabilidades_x_test)
In [68]:
print(classification_report(y_test, y_pred, target_names=['No vuelve','Vuelve']))
              precision    recall  f1-score   support

   No vuelve       0.84      0.80      0.82       121
      Vuelve       0.72      0.78      0.75        80

    accuracy                           0.79       201
   macro avg       0.78      0.79      0.78       201
weighted avg       0.79      0.79      0.79       201

In [69]:
mostrarAUCScore(ensamble_gaussiano,"Ensamble Gaussiano NB",probabilidades_x_test,y_test)
AUC para Ensamble Gaussiano NB: 0.856

Habiendo hecho el ensamble, observamos que no se tuvieron grandes diferencias en comparacion al Multinomial y Categorical, estando este tipo de ensamble en el medio. Lo que sí mejoró notablemente es su rendimiento en comparación al Gaussian NB.

Expansión de análisis: estudio del algoritmo y cuáles son los features más relevantes

El algoritmo de Naive Bayes debe calcular, a priori, las probabilidades de que una instancia pertenezca a una clase. Esto lo hace con la variable target, las "etiquetas" del set de entrenamiento. De esta manera si inicialmente tenemos más instancias de una clase que de otra tendremos más probabilidad de clasificarla de esa clase mayoritaria, al menos a priori.

In [70]:
gaussianNB.class_prior_
Out[70]:
array([0.62166667, 0.37833333])
In [71]:
np.exp(categoricalNB.class_log_prior_)
Out[71]:
array([0.62166667, 0.37833333])
In [72]:
np.exp(multinomialNB.class_log_prior_)
Out[72]:
array([0.62166667, 0.37833333])

Claramente, dado que hemos entrenado ambos modelos con la misma información de variable target, las probabilidades a priori son las mismas para los tres modelos. Podemos ver que casi dos tercios de la instancias son de la clase "No volveria"

In [73]:
features_categorical = X.drop(columns=['edad', 'precio_ticket', 'autocompletamos_edad']).columns.to_list()
features_gaussian = ['edad','precio_ticket','autocompletamos_edad']
features_multinomial = X.drop(columns=['edad', 'autocompletamos_edad']).columns.to_list()

Buscamos ahora información acerca de las probabilidades condicionales que se construyeron en el modelo. Analizaremos algunas para poder ver si se corresponden con el análisis realizado en la primer parte del trabajo.

In [74]:
i = 0
j = 0
for array in categoricalNB.feature_log_prob_:
    
    feature = features_categorical[i]
    for probabilidad in array:
        print(feature)
        if(j % 2 == 0):
            print("Dado que no volveria")
        else:
            print("Dado que volveria")
        print(np.exp(probabilidad))
        print("")
        j=j+1
    i=i+1
sufijo
Dado que no volveria
[0.83246073 0.05497382 0.11256545]

sufijo
Dado que volveria
[0.32627119 0.3220339  0.35169492]

tipo_de_sala
Dado que no volveria
[0.19109948 0.68062827 0.12827225]

tipo_de_sala
Dado que volveria
[0.28813559 0.33474576 0.37711864]

genero
Dado que no volveria
[0.83905013 0.16094987]

genero
Dado que volveria
[0.32618026 0.67381974]

amigos
Dado que no volveria
[0.87696335 0.10209424 0.02094241]

amigos
Dado que volveria
[0.59745763 0.36440678 0.03813559]

parientes
Dado que no volveria
[0.14136126 0.7617801  0.09685864]

parientes
Dado que volveria
[0.25       0.65677966 0.09322034]

Las probabilidades anteriores son las probabilidades condicionales. Condicionado al subconjunto de las personas que volverían o no volverían se calcula para cada feature la probabilidad de que tome alguno de los valores que puede tomar.

Esto se puede calcular utilizando pandas, por ejemplo para el caso del género:

In [75]:
y_df = pd.DataFrame(columns = ['volveria'], data = y)
In [76]:
X_volveria = X.iloc[y_df.loc[y_df["volveria"] == True].index]
X_volveria["genero"].value_counts(normalize = True).round(2)
Out[76]:
mujer     0.69
hombre    0.31
Name: genero, dtype: float64
In [77]:
X_no_volveria = X.iloc[y_df.loc[y_df["volveria"] == False].index]
X_no_volveria["genero"].value_counts(normalize = True).round(2)
Out[77]:
hombre    0.85
mujer     0.15
Name: genero, dtype: float64

Podemos ver que dentro de las personas que volverían, casi el 70% es mujer y dentro de las personas que no vuelven el 84% es hombre.

Este feature es bastante relevante. Por ejemplo, suponiendo que consideramos solo este feature realizaríamos las siguientes predicciones:

Si es hombre:

  • $P$(vuelve) = $P_{a priori}$(vuelve) $P$(hombre|vuelve) = 0.38 0.30 = 0.114
  • $P$(no vuelve) = $P_{a priori}$(no vuelve) $P$(hombre|no vuelve) = 0.62 0.84 = 0.52

P(vuelve) < P(no vuelve) => si es hombre no vuelve

Si es mujer:

  • $P$(vuelve) = $P_{a priori}$(vuelve) $P$(mujer|vuelve) = 0.38 0.69 = 0.26
  • $P$(no vuelve) = $P_{a priori}$(no vuelve) $P$(mujer|no vuelve) = 0.62 0.15 = 0.093

    $P$(vuelve) > $P$(no vuelve) => si es mujer vuelve

Vemos que relativamente las probabilidades son muy distintas: para los hombres, la probabilidad de que vuelva es aproximadamente 3 veces mayor que de que no vuelva y para las mujeres lo contrario.

Por este motivo consideramos que debe ser un feature relevante a la hora de clasificar a una persona en si esta volvería o no al cine a ver la secuela de la película.

Predicciones sobre el nuevo archivo

Obtenemos y preparamos el nuevo archivo realizando el mismo preprocesamiento realizado anteriormente.

In [78]:
holdout = obtenerHoldout()
ids_usuarios = np.array(holdout['id_usuario'])
holdout = prepararSetDeHoldout(holdout)
In [79]:
columnasCategoricas = ['sufijo','tipo_de_sala','genero','fila','nombre_sede']
columnasDiscretas = ['sufijo','tipo_de_sala','genero','amigos','parientes','precio_ticket','fila','nombre_sede']

holdout_categorical_NB = conversionAVariablesCodificadas(holdout,columnasCategoricas)
holdout_multinomial_NB = conversionAVariablesCodificadas(holdout,columnasDiscretas)
holdout_gaussian_NB = conversionAVariablesContinuas(holdout)
In [80]:
predicciones_holdout_categorical = categoricalNB.predict(holdout_categorical_NB)
predicciones_holdout_multinomial = multinomialNB.predict(holdout_multinomial_NB)
predicciones_holdout_gaussian = gaussianNB.predict(holdout_gaussian_NB)
In [81]:
escribirPrediccionesAArchivo(predicciones_holdout_categorical,"Categorical NB",ids_usuarios)
escribirPrediccionesAArchivo(predicciones_holdout_multinomial,"Multinomial NB",ids_usuarios)
escribirPrediccionesAArchivo(predicciones_holdout_gaussian,"Gaussian NB",ids_usuarios)

Para el ensamble gaussiano:

In [82]:
probabilidades_multinomial = multinomialNB.predict_proba(holdout_multinomial_NB)
probabilidades_categorical = categoricalNB.predict_proba(holdout_categorical_NB)
probabilidades_gaussian = gaussianNB.predict_proba(holdout_gaussian_NB)
probabilidades_holdout = np.hstack((probabilidades_multinomial, probabilidades_categorical , probabilidades_gaussian))
In [83]:
predicciones_holdout_ensamble_gaussiano = ensamble_gaussiano.predict(probabilidades_holdout)
In [84]:
escribirPrediccionesAArchivo(predicciones_holdout_ensamble_gaussiano,"Ensamble Gaussiano NB",ids_usuarios)