jupyter | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
try:
import google.colab
IN_COLAB = True
except:
IN_COLAB = False
import pandas as pd
import numpy as np
import sklearn as sk
import seaborn as sns
import pydotplus
from six import StringIO
from IPython.display import Image
from matplotlib import pyplot as plt
#TODO creo q no va:
from dict_paises import COUNTRY_ALPHA3_TO_COUNTRY_ALPHA2, COUNTRY_ALPHA2_TO_CONTINENT
from joblib import dump, load
from os.path import exists
from sklearn.model_selection import StratifiedKFold, KFold,RandomizedSearchCV, train_test_split, cross_validate
from sklearn.tree import DecisionTreeClassifier, export_graphviz, export_text
from sklearn.metrics import confusion_matrix, classification_report , f1_score, make_scorer, precision_score, recall_score, accuracy_score,f1_score
from sklearn.preprocessing import MinMaxScaler
from sklearn import tree
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split, RandomizedSearchCV, GridSearchCV, cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.metrics import accuracy_score
#Si estamos en colab tenemos que instalar la libreria "dtreeviz" aparte.
if IN_COLAB == True:
!pip install 'dtreeviz'
import dtreeviz as dtreeviz
#Para eliminar los warnings
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
warnings.simplefilter(action='ignore', category=UserWarning)
import tensorflow as tf
from tensorflow import keras
from keras.utils.vis_utils import plot_model
from keras.wrappers.scikit_learn import KerasClassifier #Libreria para usarg Grid Search con kerss
Constantes
# Constantes
JOBS=-2
SEED=9
np.random.seed(SEED)
tf.random.set_seed(SEED)
importo el dataframe original para tener los ids
hotelsdf_pruebasOriginal = pd.read_csv("./hotels_test.csv")
Importamos los dataframes ya filtrados que generamos en el checkpoint 1. De esta forma evitamos tener todo el codigo de homologacion de dataframes de testeo y train aqui de nuevo
hotelsdf_train_filtrado = pd.read_csv("hotels_filtrado_train.csv")
hotelsdf_testeo_filtrado = pd.read_csv("hotels_filtrado_test.csv")
set_test = set(hotelsdf_testeo_filtrado.columns)
set_modelo = set(hotelsdf_train_filtrado.columns)
missing = list(sorted(set_test - set_modelo))
added = list(sorted(set_modelo - set_test))
print('Faltan en arbol:', missing)
print('Sobran en arbol:', added)
Guardo datos antes de separacion train test
Se genera un dataset con los datos necesarios para predecir la cancelacion y creamos un dataset conteniendo el target, para luego, generar conjuntos de test y train
Considerando que previamente se vienen modificando los datos y aplicandoles un encoding del tipo One Hot, solo restaria realizar un escalado sobre las variables cuantitativas. No habra problema al aplicarlo sobre ningunda de estas debido a que todas fueron previamente analizadas en el checkpoint 1 y eliminamos outliers que pueden representar un problema en el analisis
hotelsdf_modelo_x=hotelsdf_train_filtrado.drop(['is_canceled'], axis='columns', inplace=False)
hotelsdf_modelo_y = hotelsdf_train_filtrado['is_canceled'].copy()
x_train, x_test, y_train, y_test = train_test_split(hotelsdf_modelo_x,
hotelsdf_modelo_y,
test_size=0.3, #proporcion 70/30
random_state=SEED) #Semilla 9, como el Equipo !!
Buscamos los valores que no fueron generados por el one hot encoder
x_train.columns
valoresNoBinarios = ['lead_time', 'arrival_year', 'arrival_week_number', 'arrival_month_day',
'weekend_nights_num', 'week_nights_num', 'adult_num', 'children_num',
'babies_num', 'previous_cancellations_num',
'booking_changes_num', 'days_in_waiting_list',
'average_daily_rate', 'required_car_parking_spaces_num',
'special_requests_num', 'dias_totales']
#Tenemos que escalar todos los valores de nuestro data set (excepto los valores producidos por el one hot encoding
sScaler = StandardScaler()
sScaler.fit(pd.DataFrame(x_train[valoresNoBinarios]))
x_train_transform_1=sScaler.transform(pd.DataFrame(x_train[valoresNoBinarios]))
x_test_transform_1=sScaler.transform(pd.DataFrame(x_test[valoresNoBinarios]))
hotelsdf_testeo_transform=sScaler.transform(pd.DataFrame(hotelsdf_testeo_filtrado[valoresNoBinarios]))
#Creamos un nuevo dataframe con los valores escalados
x_train_escalado = x_train.copy()
x_test_escalado = x_test.copy()
hotelsdf_testeo_escalado = hotelsdf_testeo_filtrado.copy()
#Le asignamos los nuevos valores escalados y mantenemos los valores del one hot encoding
for i in range(len(valoresNoBinarios)):
x_train_escalado[valoresNoBinarios[i]]=x_train_transform_1[:,i]
x_test_escalado[valoresNoBinarios[i]]=x_test_transform_1[:,i]
hotelsdf_testeo_filtrado[valoresNoBinarios[i]] = hotelsdf_testeo_transform[:,i]
Creamos una red muy simple con una unica capa oculta y funcion de activacion relu
cant_clases = 1
#d_in=len(y_train)
d_in=len(x_train_escalado.columns)
modelo_hotels_1 = keras.Sequential([
keras.layers.Dense(8,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(cant_clases, activation='sigmoid'),
])
modelo_hotels_1.summary()
La entrenamos con el optimizador Nadam puesto que vimos en clase que es el mejor.
modelo_hotels_1.compile(
optimizer=keras.optimizers.Nadam(learning_rate=0.01),
loss='binary_crossentropy',
# metricas para ir calculando en cada iteracion o batch
metrics=['AUC'],
)
cant_epochs=80
historia_modelo_hotel_1=modelo_hotels_1.fit(x_train_escalado,y_train,epochs=cant_epochs,batch_size=16,verbose=False)
y_pred = modelo_hotels_1.predict(x_test_escalado)
y_predic_cat_ej1 = np.where(y_pred>0.7,1,0)
historia_modelo_hotels_1=modelo_hotels_1.fit(x_train_escalado,y_train,epochs=cant_epochs,batch_size=16,verbose=False)
Miramos la metrica AUC en funcion de la cantidad de epocas para enocntrar un valor aceptable
epochs = range(cant_epochs)
plt.plot(epochs, historia_modelo_hotels_1.history['auc'], color='orange', label='AUC')
plt.xlabel("epochs")
plt.ylabel("AUC")
plt.legend()
Predecimos
y_pred_modelo_1 = modelo_hotels_1.predict(x_test_escalado)
y_predic_cat_modelo_1 = np.where(y_pred_modelo_1>0.50,1,0)
Mostramos los resultados de este primer modelo
print(classification_report(y_test,y_predic_cat_modelo_1))
print('F1-Score: {}'.format(f1_score(y_test, y_predic_cat_modelo_1, average='binary')))
cm = confusion_matrix(y_test,y_predic_cat_modelo_1)
sns.heatmap(cm, cmap='Blues',annot=True,fmt='g')
plt.xlabel('predecido')
plt.ylabel('verdadero')
Los resultados son relativamente buenos y no se ve que el modelo este muy sesgado. Aumentamos la cantidad de nueronas para intentar mejorar el f1_score
cant_clases = 1
d_in=len(x_train_escalado.columns)
modelo_hotels_2= keras.Sequential([
keras.layers.Dense(8,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(16,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(32,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(64,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(cant_clases, activation='sigmoid'),])
modelo_hotels_2.compile(
optimizer=keras.optimizers.Nadam(learning_rate=0.01),
loss='binary_crossentropy',
# metricas para ir calculando en cada iteracion o batch
metrics=['AUC'],
)
cant_epochs=80
historia_modelo_hotels_2=modelo_hotels_2.fit(x_train_escalado,y_train,epochs=cant_epochs,batch_size=16,verbose=False)
epochs = range(cant_epochs)
plt.plot(epochs, historia_modelo_hotels_2.history['auc'], color='orange', label='AUC')
plt.xlabel("epochs")
plt.ylabel("auc")
plt.legend()
y_pred_modelo_2 = modelo_hotels_2.predict(x_test_escalado)
y_pred_modelo_2
Graficamos
y_predic_cat_modelo_2 = np.where(y_pred_modelo_2>0.50,1,0)
print(classification_report(y_test,y_predic_cat_modelo_2))
print('F1-Score: {}'.format(f1_score(y_test, y_predic_cat_modelo_2, average='binary')))
cm = confusion_matrix(y_test,y_predic_cat_modelo_2)
sns.heatmap(cm, cmap='Blues',annot=True,fmt='g')
plt.xlabel('predecido')
plt.ylabel('verdadero')
El f1_score practicamente no mejoro con el aumnento de neruronas y capas. Sin embargo en ambos modelos (modelo_hotels_1 y 2) vemos que a partir de las 40 epocas el AUC practicamente no varia. Entonces bajamos la cantidad de epocas hasta ese valor para obtener una red mas optima Y tambien quito algunas capas para que la red sea mas simple porque no tiene sentido dejar una red mas compleja que no mejora el f1_score
cant_clases = 1
d_in=len(x_train_escalado.columns)
modelo_hotels_3= keras.Sequential([
keras.layers.Dense(8,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(16,input_shape=(d_in,),activation ='relu'),
keras.layers.Dense(cant_clases, activation='sigmoid'),])
modelo_hotels_3.compile(
optimizer=keras.optimizers.Nadam(learning_rate=0.01),
loss='binary_crossentropy',
# metricas para ir calculando en cada iteracion o batch
metrics=['AUC'],
)
cant_epochs=40
historia_modelo_hotels_3=modelo_hotels_3.fit(x_train_escalado,y_train,epochs=cant_epochs,batch_size=16,verbose=False)
Vemos el AUC contra la cantidad de epocas
epochs = range(cant_epochs)
plt.plot(epochs, historia_modelo_hotels_3.history['auc'], color='orange', label='AUC')
plt.xlabel("epochs")
plt.ylabel("auc")
plt.legend()
y_pred_modelo_3 = modelo_hotels_3.predict(x_test_escalado)
y_pred_modelo_3
y_predic_cat_modelo_3 = np.where(y_pred_modelo_3>0.50,1,0)
Graficamos
print(classification_report(y_test,y_predic_cat_modelo_3))
print('F1-Score: {}'.format(f1_score(y_test, y_predic_cat_modelo_3, average='binary')))
cm = confusion_matrix(y_test,y_predic_cat_modelo_3)
sns.heatmap(cm, cmap='Blues',annot=True,fmt='g')
plt.xlabel('predecido')
plt.ylabel('verdadero')
Con la mitad de epocas y menor cantidad de capas y neuronas el valor del f1_score es practicamente el mismo. Nos quedamos con esta ultima red
dump(modelo_hotels_3, 'modelos/red_neuronal_3.joblib')
y_pred_testeo = modelo_hotels_3.predict(hotelsdf_testeo_filtrado)
y_pred_testeo
y_pred_testeo_cat = np.where(y_pred_testeo>0.4,1,0)
df_resultados_pred = pd.DataFrame.from_records(y_pred_testeo_cat,columns = ["resultado"])
df_resultados_pred
df_submission = pd.DataFrame({'id': hotelsdf_pruebasOriginal['id'], 'is_canceled': df_resultados_pred["resultado"]})
df_submission.to_csv('submissions/red_neuronal_3.csv', index=False)
df_submission
df_submission.head()
En esta etapa vamos a realizar unas series de validaciones cruzadas en la busqueda de encontrar el mejor resultado
Para usar la libreria Keras Classifier necesitamos crear una funcion que cree una modelo.
loss='binary_crossentropy'
metrics=['AUC']
optimizer="adam"
def creador_modelo(learning_rate = 0.1,
activation = 'sigmoid',
output = 2,
hidden_layers = 2
):
model = keras.Sequential()
model.add(keras.layers.Dense(5, activation=activation, input_shape=(d_in,)))
for i in range(hidden_layers):
model.add(keras.layers.Dense(output, activation=activation))
model.add(keras.layers.Dense(1, activation=activation))
model.compile(
optimizer=optimizer,
loss=loss,
metrics=metrics,
)
return model
Vamos a empezar con una baja cantidad de epochs y batch_size
model = KerasClassifier(build_fn=creador_modelo,
verbose=1)
param_grid = {
"hidden_layers" : [1, 5, 10, 15, 20],
"output" : [1, 2, 4, 8, 32, 64],
"batch_size" : [5, 10, 20],
"epochs" : [50, 100, 150],
"activation": ["sigmoid", "relu", "softmax", "softplus", "elu", ]
}
rs = RandomizedSearchCV(estimator=model, param_distributions=param_grid,n_jobs=JOBS, cv=3,n_iter=10)
if exists('modelos/rs_fit.joblib') == False:
rs_fit = rs.fit(X = x_train_escalado, y = y_train)
dump(rs_fit, 'modelos/rs_fit.joblib')
else:
rs_fit = load('modelos/rs_fit.joblib')
rs_fit.best_params_
modelo_rs = keras.Sequential()
modelo_rs.add(keras.layers.Dense(5, activation=rs_fit.best_params_["activation"], input_shape=(d_in,)))
for i in range(rs_fit.best_params_["hidden_layers"]):
# Add one hidden layer
modelo_rs.add(keras.layers.Dense(rs_fit.best_params_["output"], activation=rs_fit.best_params_["activation"]))
modelo_rs.add(keras.layers.Dense(1, activation="sigmoid"))
modelo_rs.compile(
optimizer=optimizer,
loss=loss,
metrics=metrics,
)
cant_epochs=rs_fit.best_params_["epochs"]
batch_size=rs_fit.best_params_["batch_size"]
historia_modelo_hotel_4=modelo_rs.fit(x_train_escalado,y_train,
epochs=cant_epochs,
batch_size=batch_size,verbose=False)
epochs = range(cant_epochs)
plt.plot(epochs, historia_modelo_hotel_4.history['auc'], color='orange', label='AUC')
plt.xlabel("epochs")
plt.ylabel("AUC")
plt.legend()
y_pred = modelo_rs.predict(x_test_escalado)
y_predic_cat_modelo4 = np.where(y_pred>0.5,1,0)
print(classification_report(y_test,y_predic_cat_modelo_1))
print('F1-Score: {}'.format(f1_score(y_test, y_predic_cat_modelo4, average='binary')))
cm = confusion_matrix(y_test,y_predic_cat_modelo_1)
sns.heatmap(cm, cmap='Blues',annot=True,fmt='g')
plt.xlabel('predecido')
plt.ylabel('verdadero')
y_pred_testeo = modelo_rs.predict(hotelsdf_testeo_filtrado)
y_pred_testeo_cat = np.where(y_pred_testeo>0.5,1,0)
df_resultados_pred = pd.DataFrame.from_records(y_pred_testeo_cat,columns = ["resultado"])
df_submission = pd.DataFrame({'id': hotelsdf_pruebasOriginal['id'], 'is_canceled': df_resultados_pred["resultado"]})
df_submission.to_csv('submissions/red_neuronal_rs.csv', index=False)
df_submission.head()