Skip to content

Commit

Permalink
Merge pull request #49 from Los-persistentes-de-Pearson/crisisEmocional
Browse files Browse the repository at this point in the history
Crisis emocional
  • Loading branch information
lima-limon-inc authored Apr 28, 2023
2 parents 4b5a176 + 49afe34 commit d143c06
Show file tree
Hide file tree
Showing 16 changed files with 10,209 additions and 19,095 deletions.
6,137 changes: 6,137 additions & 0 deletions 7506R-1C2023-GRUPO09-CHP02.ipynb

Large diffs are not rendered by default.

865 changes: 865 additions & 0 deletions 7506R-1C2023-GRUPO09-CHP02.md

Large diffs are not rendered by default.

15,845 changes: 0 additions & 15,845 deletions 7506R-1C2023-GRUPO09.ipynb

This file was deleted.

12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
# 7506R-1C2023-GRUPO09
## Informe

## Consigna checkpoint 2
- [X] Construir árboles de decisión y optimizar sus hiperparámetros mediante k-fold Cross Validation para obtener la mejor performance. ¿Cuántos folds utilizaron? ¿Qué métrica consideran adecuada para buscar los parámetros?
- [X] Graficar el árbol de decisión con mejor performance encontrado en el punto anterior. Si es muy extenso mostrar una porción representativa.
- [ ] Analizar el árbol de decisión seleccionado describiendo los atributos elegidos, y decisiones evaluadas (explicar las primeras reglas obtenidas).
- [X] Evaluar la performance del modelo en entrenamiento y validación, explicar todas las métricas y mostrar la matriz de confusión.
- [X] Generar predicciones con el conjunto de test y realizar los submits correspondientes en la competencia de Kaggle.
Informe:
[Informe checkpoint 2](informe/7506R_TP1_GRUPO09_CHP2_REPORTE.pdf)

## Repo del equipo #9

![Karl Pearson](informe/images/Karl_Pearson.jpg)
![Karl Pearson](informe/images/Karl_Pearson.jpg)
128 changes: 39 additions & 89 deletions checkpoint2.md
Original file line number Diff line number Diff line change
Expand Up @@ -561,31 +561,25 @@ Iniciamos con una profundidad maxima arbitraria, en este caso 20 y creamos un ar
Dicho modelo sera uno generado directamente tomando en cuenta todos los valores y sin generar ningun tipo de poda, para observar como se comporta un modelo sin tratar

```python
'''
PROFUNDIDAD_MAX = 20

tree_model = tree.DecisionTreeClassifier(criterion="gini",
max_depth = PROFUNDIDAD_MAX)
model = tree_model.fit(X = x_train, y = y_train)
'''

```


Una vez entrenado el modelo realizamos una predicción con el mismo

```python
'''
y_pred = model.predict(x_test)
y_pred
'''
```

```python
'''
ds_resultados=pd.DataFrame(zip(y_test,y_pred),columns=['test','pred'])
ds_resultados
'''
```

Estas columns representan 20% de nuestro dataframe que fue dedicado al testeo del modelo
Expand All @@ -594,28 +588,23 @@ Estas columns representan 20% de nuestro dataframe que fue dedicado al testeo de
Vamos a graficar la matriz de confusion para visualizar los resultados de nuesto modelo:

```python
'''
tabla=confusion_matrix(y_test, y_pred)
sns.heatmap(tabla,cmap='GnBu',annot=True,fmt='g')
plt.xlabel('Predicted')
plt.ylabel('True')
'''
```

Presentamos las reglas conseguidas en árbol no optizado:

```python
'''
reglas = export_text(tree_model, feature_names=list(hotelsdfArbol_x.columns.tolist()))
print(reglas)
'''
```

A continuacion vamos a graficar el arbol resultante: \
(**Advertencia**: Suele tardar unos minutos en terminar de renderizar la imagen)

```python
'''
plt.figure(figsize=(100,100))

tree_plot_completo=tree.plot_tree(model,
Expand All @@ -624,21 +613,12 @@ tree_plot_completo=tree.plot_tree(model,
rounded=True,
class_names=['Not Canceled','Is canceled']) #model.classes_
plt.show(tree_plot_completo)
'''

```
```python
'''
dump(model, 'modelos/arbolIneficiente.joblib')
'''
```

Con la imagen se ve que el arbol resultante tiene unas dimensiones exageradas, vemos ademas que tiene una profundidad de 20 como especificamos

Vemos que en un árbol sin optimizar de profundidad 20 y sin configurar una mejora en los hiperparametros obtenemos las siguientes metricas:

```python
'''
accuracy=accuracy_score(y_test,y_pred)
recall=recall_score(y_test,y_pred)
f1=f1_score(y_test,y_pred,)
Expand All @@ -648,17 +628,29 @@ print("Accuracy: "+str(accuracy))
print("Recall: "+str(recall))
print("Precision: "+str(precision))
print("f1 score: "+str(f1))
'''
```

```python
'''
#dump(model, 'modelos1/arbolIneficiente.joblib')
#Cargamos el modelo de una de nuestras corrida. Este modelo no deberia variar mucho entre corrida y corrida
model = load('modelos/arbolIneficiente.joblib')
```

```python
#Realizamos una predicción sobre el set de test
y_pred = model.predict(hotelsdfTesteo)
#Valores Predichos
y_pred
'''
```
```python
df_submission = pd.DataFrame({'id': hotelsdfTesteoOriginal['id'], 'is_canceled': y_pred})
df_submission.head()
```

```python
df_submission.to_csv('submissions/arbol_decisiones_ineficiente.csv', index=False)
```

Con este modelo, obtuvimos el siguiente resultado:

![PrimeraEntrega](informe/images/primeraPrediccion.jpg)
Expand All @@ -675,7 +667,6 @@ Tomamos 15 combinaciones posibles entre los parametros existentes y buscamos la
Nos basamos en los siguientes parametros:

```python
'''
combinaciones=15
limite_hojas_nodos = list(range(2, 50))
valor_poda = 0.0001 #0.0007
Expand All @@ -702,63 +693,59 @@ randomcv = RandomizedSearchCV(estimator=base_tree,
n_iter=combinaciones)

randomcv.fit(x_train,y_train)
'''
```

Mostramos los mejores hiperparametros devueltos por el arbol y el valor del f1_score

```python
'''
print("Mostramos los mejores resultados: ")
print(randomcv.best_params_)
print()
print("Mostramos el mejor resultado obtenido de busqueda aleatoria: ")
print("f1_score = ",randomcv.best_score_)
'''
```

Algunos valores obtenidos del algoritmo

```python
'''
randomcv.cv_results_['mean_test_score']
'''
```

## Predicción y Evaluación del Modelo con mejores hiperparámetros

Generamos el árbol con los hiperparametros que optimizan su eficiencia y a su vez presentamos el conjunto de valores con su peso relativo a la toma de la decisión


Cargamos el mejor arbol que encontramos (explicado en la seccion de validacion cruzada)

```python
arbol_mejores_parametros = load('modelos/arbolEficiente.joblib')
```

```python
'''
arbol_mejores_parametros=DecisionTreeClassifier().set_params(**randomcv.best_params_)
arbol_mejores_parametros.fit(x_train,y_train)
'''
```

*Conjunto de reglas:*

```python
'''
features_considerados = hotelsdfArbol_x.columns.to_list()
best_tree = randomcv.best_estimator_
feat_imps = best_tree.feature_importances_

for feat_imp,feat in sorted(zip(feat_imps,features_considerados)):
if feat_imp>0:
print('{}: {}'.format(feat,feat_imp))
'''
```

Es importante destacar tres de las variables seleccionadas en la primera parte de nuestro analisis (Checkpoint 1): lead_time, average_daily_rate y previous_cancelations_nums estan enmarcadas dentro de las diez caracteristicas que aportan màs información en la construcción del árbol
Es importante destacar que tres de las variables seleccionadas en la primera parte de nuestro analisis (Checkpoint 1): lead_time, average_daily_rate y previous_cancelations_nums estan enmarcadas dentro de las diez caracteristicas que aportan màs información en la construcción del árbol

*Mostramos las reglas internas del árbol:*

```python
'''
reglas = export_text(arbol_mejores_parametros, feature_names=list(features_considerados))
print(reglas)
'''
```

Se puede observar una considerable simplificacion en la ramificacion de las reglas de este árbol comparado contra el primer árbol generado en el análisis
Expand All @@ -769,7 +756,6 @@ Se puede observar una considerable simplificacion en la ramificacion de las regl
Mostramos los primeros cinco niveles del árbol optimazado y observamos una diferencia con el primer árbol generado en el analisis:

```python
'''
dot_data = StringIO()
export_graphviz(arbol_mejores_parametros, out_file=dot_data,
filled=True, rounded=True,
Expand All @@ -780,44 +766,39 @@ export_graphviz(arbol_mejores_parametros, out_file=dot_data,

graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
Image(graph.create_png())
'''
```

Considerando lo antes mencionado podemos apreciar que:
1. El primer nodo particiona segun el tipo de deposito: sin rembolso, donde, la gente tiende a mantener la reserva y con rembolso donde se tiende a cancelar
2. El segundo nivel árbol toma en consideración el lead time y el numero de cambios en la reserva. Con un lead time menor a 11.5 tiene una menor cantidad de reservas canceladas, mientras, en el otro nodo clasifica cancelado si el numero de cambios en la reserva es menor que cero
3. En un tercer nivel observamos que las variables que más aportan informacion son: previous cancelation number, market segment type online TA, customer type trasient party y arrival month day 13
2. El segundo nivel árbol toma en consideración la cantidad de espacios de estacionamiento requerido y si el tipo de cliente es Transient Party. La primera variable es discreta; la segunda variable es binaria (o vale 1 o vale 0). Esta ultima fue generada en el proceso de one hot encoding
3. En un tercer nivel observamos que las variables que más informacion aportan son: previous cancelation number y hotel name


### Prediccion con split de train

Hacemos una primera evaluación del árbol haciendo uso de los datos de prueba y medimos su desempeño

```python
'''
y_pred= arbol_mejores_parametros.predict(x_test)
print('F1-Score: {}'.format(f1_score(y_test, y_pred, average='binary')))
cm = confusion_matrix(y_test,y_pred)
sns.heatmap(cm, cmap='Blues',annot=True,fmt='g')
plt.xlabel('Predecidos')
plt.ylabel('Verdaderos')
plt.title("Desempeño del modelo con datos de prueba")
'''
```

*Un vistazo al primer conjunto de prediccione:*

```python
'''
arbol_mejores_parametros.predict_proba(x_test)
'''
```

## Entrenamiento Cross Validation

Procedemos a realizar entrenamiento del árbol mediante el metodo de la validación cruzada en 10 folds considerando que fue como se entreno previamente al árbol mas optimo. Esto buscando siempre mantener la metrica F1 en su valor más alto, como también comprobar que el árbol mantiene un desempeño esperado y detectar posibles casos de *Overfitting o Underfitting*

```python
'''
kfoldcv =StratifiedKFold(n_splits=folds)
scorer_fn = make_scorer(sk.metrics.f1_score)

Expand All @@ -826,85 +807,54 @@ resultados = cross_validate(arbol_mejores_parametros,x_train, y_train, cv=kfoldc
metricsCV = resultados['test_score']

arbol_mejor_performance = resultados['estimator'][np.where(metricsCV==max(metricsCV))[0][0]]
'''
```

```python
'''
metric_labelsCV = ['F1 Score']*len(metricsCV)
sns.set_context('talk')
sns.set_style("darkgrid")
plt.figure(figsize=(8,8))
sns.boxplot(metricsCV)
plt.title("Modelo entrenado con 10 folds")
'''
```

```python
'''
y_pred= arbol_mejor_performance.predict(x_test)
print(classification_report(y_test,y_pred))
print('F1-Score: {}'.format(f1_score(y_test, y_pred, average='binary')))
cm = confusion_matrix(y_test,y_pred)
sns.heatmap(cm, cmap='Blues',annot=True,fmt='g')
plt.xlabel('Predicted')
plt.ylabel('True')
'''
```

# Busqueda de hiperparametros
Con modificaciones de valores para mejorar resultados
limite_hojas_nodos = list(range(2, 50))
valor_poda = 0.0001 #0.0007
profundidad = list(range(0,40))


## Limite de hojas modificado
Se determina que de la anterior busqueda de hiperparametros mediante la validacion cruzada, el ultimo arbol obtenido es el arbol mas eficiente entrenado hasta el momento.\
Es por esto que lo guardamos para que pueda ser cargado para uso posterior

```python
'''
Tu codigo aqui
'''
#dump(arbol_mejores_parametros, 'modelos/arbolEficiente.joblib')
#Cargamos el modelo de una de nuestras corrida. Este modelo no deberia variar mucho entre corrida y corrida
```

```python
'''
dump(model, 'modelos/arbolHojas.joblib')
'''
```

## Poda modificada

```python
'''
Tu codigo aqui
'''
```

```python
'''
dump(model, 'modelos/arbolPoda.joblib')
'''
#Realizamos una predicción sobre el set de test
y_pred = arbol_mejores_parametros.predict(hotelsdfTesteo)
#Valores Predichos
y_pred
```

## Profundidad modificada

```python
'''
Tu codigo aqui
'''
df_submission = pd.DataFrame({'id': hotelsdfTesteoOriginal['id'], 'is_canceled': y_pred})
df_submission.head()
```

```python
'''
dump(model, 'modelos/arbolProfundidad.joblib')
'''
df_submission.to_csv('submissions/arbol_decisiones_eficiente.csv', index=False)
```

---

# Conclusión

1. Al comparar los dos modelos construidos, se observó una mejora considerable en el segundo modelo en factores como la performance y las métricas en comparación con el primero. Esto sugiere que se pudo optimizar significativamente el modelo mediante la incorporación de tecnicas como: ramdomized cross search
2. Las métricas del árbol se mejoraron mediante la optimización del F1 score, el cual fue seleccionado debido a la naturaleza del problema en el que no había un motivo particular para seleccionar una métrica específica (como recall o precision).
3. A pesar de la poda y la reducción de la libertad del árbol para extenderse, se logró una mejora significativa en su métrica F1. Esto demuestra que la poda y la limitación de la extensión del árbol no necesariamente afectan negativamente su rendimiento, sino que pueden mejorar la capacidad de generalización del modelo.
4. Se realizaron repetidas pruebas sobre el modelo buscando mejorar el f1 score, de todos estos intentos se alamaceno el que mejor balanceaba eficiencia con f1 score.
File renamed without changes.
File renamed without changes.
Binary file not shown.
Loading

0 comments on commit d143c06

Please sign in to comment.