Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| import joblib | |
| import os | |
| from sklearn.model_selection import train_test_split, GridSearchCV | |
| from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier | |
| def ejecutar_fine_tuning(): | |
| print("========================================================================") | |
| print("⚙️ INICIANDO SINTONIZACIÓN FINA (FINE-TUNING) DE MODELOS TABULARES") | |
| print("========================================================================\n") | |
| # 1. Cargar el dataset final preparado | |
| ruta_datos = 'datos_procesados/dataset_preparado_ml.csv' | |
| if not os.path.exists(ruta_datos): | |
| print(f"[ERROR] No se encuentra el dataset en {ruta_datos}") | |
| return | |
| df_ml = pd.read_csv(ruta_datos) | |
| # 2. Separar variables | |
| # Asumimos que el dataset ya está limpio de chivatos gracias al pipeline anterior | |
| X = df_ml.drop(columns=['churn'], errors='ignore') | |
| y = df_ml['churn'] | |
| X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42, stratify=y) | |
| # 3. Definir los finalistas y sus cuadrículas de hiperparámetros | |
| top_3_nombres = ['Gradient Boosting', 'RF - Profundo (Ramas ∞, Hojas 1)', 'RF - Intermedio (Ramas 12, Hojas 10)'] | |
| diccionario_grids = { | |
| "Gradient Boosting": ( | |
| GradientBoostingClassifier(random_state=42), | |
| { | |
| 'n_estimators': [100, 200], | |
| 'learning_rate': [0.05, 0.1, 0.2], | |
| 'max_depth': [3, 5, 7] | |
| } | |
| ), | |
| "RF - Profundo (Ramas ∞, Hojas 1)": ( | |
| RandomForestClassifier(random_state=42, n_jobs=-1), | |
| { | |
| 'n_estimators': [100, 200, 300], | |
| 'max_depth': [None, 20, 30], | |
| 'min_samples_split': [2, 5], | |
| 'min_samples_leaf': [1, 2] | |
| } | |
| ), | |
| "RF - Intermedio (Ramas 12, Hojas 10)": ( | |
| RandomForestClassifier(random_state=42, n_jobs=-1), | |
| { | |
| 'n_estimators': [100, 200], | |
| 'max_depth': [10, 15, None], | |
| 'min_samples_split': [2, 5], | |
| 'min_samples_leaf': [2, 10] | |
| } | |
| ) | |
| } | |
| resultados_finetuning = [] | |
| mejores_modelos = {} | |
| # 4. Bucle de Optimización | |
| for nombre in top_3_nombres: | |
| print(f"🔬 Optimizando: {nombre}...") | |
| modelo_base, parametros = diccionario_grids[nombre] | |
| grid_search = GridSearchCV( | |
| estimator=modelo_base, param_grid=parametros, scoring='f1', cv=3, n_jobs=-1, verbose=0 | |
| ) | |
| grid_search.fit(X_train, y_train) | |
| mejor_modelo = grid_search.best_estimator_ | |
| mejores_modelos[nombre] = mejor_modelo | |
| y_pred_opt = mejor_modelo.predict(X_test) | |
| f1_opt = f1_score(y_test, y_pred_opt, zero_division=0) | |
| acc_opt = accuracy_score(y_test, y_pred_opt) | |
| prec_opt = precision_score(y_test, y_pred_opt, zero_division=0) | |
| rec_opt = recall_score(y_test, y_pred_opt, zero_division=0) | |
| print(f" -> Mejores parámetros: {grid_search.best_params_}") | |
| print(f" -> Nuevo F1-Score: {f1_opt:.4f}\n") | |
| resultados_finetuning.append({ | |
| "Modelo Optimizado": nombre + " (Tuned)", | |
| "Accuracy": acc_opt, | |
| "Precision": prec_opt, | |
| "Recall": rec_opt, | |
| "F1-Score": f1_opt | |
| }) | |
| # 5. Generar y guardar la gráfica final | |
| df_final = pd.DataFrame(resultados_finetuning).sort_values(by="F1-Score", ascending=False) | |
| df_melted = df_final.melt(id_vars="Modelo Optimizado", var_name="Métrica", value_name="Puntuación") | |
| plt.figure(figsize=(14, 7)) | |
| ax = sns.barplot(data=df_melted, x="Modelo Optimizado", y="Puntuación", hue="Métrica", palette="Set2") | |
| plt.title("Comparativa de Rendimiento: Modelos Finalistas Optimizados", fontsize=16, fontweight='bold') | |
| plt.ylim(0, 1.1) | |
| plt.ylabel("Puntuación (0 a 1)") | |
| plt.xlabel("") | |
| for p in ax.patches: | |
| altura = p.get_height() | |
| if altura > 0: | |
| ax.annotate(f"{altura:.3f}", (p.get_x() + p.get_width() / 2., altura), | |
| ha='center', va='bottom', fontsize=10, fontweight='bold', color='#333333', | |
| xytext=(0, 5), textcoords='offset points') | |
| plt.legend(title="Métricas de Evaluación", bbox_to_anchor=(1.02, 1), loc='upper left') | |
| plt.tight_layout() | |
| # Guardamos la gráfica en lugar de solo mostrarla | |
| os.makedirs('outputs/charts', exist_ok=True) | |
| ruta_grafica = 'outputs/charts/comparativa_finetuning.png' | |
| plt.savefig(ruta_grafica, dpi=300) | |
| print(f"📊 Gráfica guardada en: {ruta_grafica}") | |
| # 6. Guardar el Campeón Absoluto | |
| nombre_campeon = df_final.iloc[0]["Modelo Optimizado"].replace(" (Tuned)", "") | |
| modelo_campeon = mejores_modelos[nombre_campeon] | |
| ruta_modelo = 'modelos/modelo_rf_optimizado.pkl' | |
| os.makedirs(os.path.dirname(ruta_modelo), exist_ok=True) | |
| joblib.dump(modelo_campeon, ruta_modelo) | |
| print(f"\n👑 CAMPEÓN ABSOLUTO: {nombre_campeon}") | |
| print(f"💾 Modelo guardado y listo para producción en: '{ruta_modelo}'") | |
| if __name__ == "__main__": | |
| ejecutar_fine_tuning() |