Por Jose R. Zapata
Ultima actualización: 24/May/2025
La validación de modelos es un proceso crucial en el desarrollo de modelos de machine learning. Asegura que el modelo no solo se ajusta bien a los datos de entrenamiento, sino que también generaliza adecuadamente a datos no vistos.
Este proceso permite identificar problemas como el sobreajuste (overfitting), donde el modelo aprende demasiado bien los datos y sus errores en el conjunto de entrenamiento y falla en generalizar a nuevos datos.
📚 Importar librerias
# base libraries for data science
import warnings
import pandas as pd
from deepchecks.tabular import Dataset
from deepchecks.tabular.suites import model_evaluation
from joblib import dump
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.metrics import f1_score, precision_score, recall_score, roc_auc_score
from sklearn.model_selection import RandomizedSearchCV, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
warnings.filterwarnings("ignore", category=FutureWarning)
warnings.filterwarnings("ignore", category=RuntimeWarning)
La evaluación de modelos (model evaluation), es el proceso de analizar y verificar el rendimiento de un modelo de machine learning. Este proceso es necesario en los proyectos de machine learning en cualquier momento en que se desee evaluar el modelo. Su importancia radica en permitir un análisis exhaustivo del rendimiento del modelo antes de su despliegue, ayudar en la selección y optimización de modelos al permitir comparar su desempeño, y verificar cómo se comporta el modelo con nuevos conjuntos de datos, incluyendo la comparación con datos anteriores. A través de la evaluación del modelo, se pueden identificar problemas cruciales como el sobreajuste (overfitting) al comparar el rendimiento en conjuntos de entrenamiento y prueba, detectar errores sistemáticos, identificar segmentos de datos donde el modelo rinde mal, o verificar si el modelo utiliza bien las características. Esto es fundamental para garantizar la fiabilidad y el rendimiento del modelo antes de ponerlo en producción y para mantener su calidad a lo largo del tiempo.
# Leer datos desde un URL
url_data = "https://www.openml.org/data/get_csv/16826755/phpMYEkMl"
dataset = pd.read_csv(url_data, low_memory=False, na_values="?")
Definicion de tipos de datos
# Features numericas
cols_numeric_float = ["age", "fare"]
cols_numeric_int = ["sibsp", "parch"]
cols_numeric = cols_numeric_float + cols_numeric_int
# Features categoricas
cols_categoric = ["sex", "embarked"]
cols_categoric_ord = ["pclass"]
cols_categorical = cols_categoric + cols_categoric_ord
Categoricas
dataset[cols_categoric] = dataset[cols_categoric].astype("category")
dataset["pclass"] = pd.Categorical(dataset["pclass"], categories=[3, 2, 1], ordered=True)
Numericas
dataset[cols_numeric_float] = dataset[cols_numeric_float].astype("float")
dataset[cols_numeric_int] = dataset[cols_numeric_int].astype("int8")
Variable Target
target = "survived"
dataset[target] = dataset[target].astype("int8")
Si existen duplicados en el dataset, es importante eliminarlos para evitar cualquier sesgo en el conjunto de datos o fuga de datos (data leak) cuando se entrena un modelo de aprendizaje automático.
dataset = dataset.drop_duplicates()
Train / Test split
# split data into features and target
X_features = dataset.drop(target, axis="columns")
Y_target = dataset[target]
# 80% train, 20% test
x_train, x_test, y_train, y_test = train_test_split(
X_features, Y_target, stratify=Y_target, test_size=0.2, random_state=42
)
👨🏭 Feature Engineering
numeric_pipe = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="median")),
]
)
categorical_pipe = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder()),
]
)
categorical_ord_pipe = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OrdinalEncoder()),
]
)
preprocessor = ColumnTransformer(
transformers=[
("numeric", numeric_pipe, cols_numeric),
("categoric", categorical_pipe, cols_categoric),
("categoric ordinal", categorical_ord_pipe, cols_categoric_ord),
]
)
Create pipeline
data_model_pipeline = Pipeline(
steps=[("preprocessor", preprocessor), ("model", RandomForestClassifier())]
)
Hyperparameter tunning
Select the best hyperparameters for the models selected in the previous step.
Random Forest
score = "recall"
hyperparameters = {
"model__max_depth": [4, 5, 7, 9, 10],
"model__max_features": [2, 3, 4, 5, 6, 7, 8, 9],
"model__criterion": ["gini", "entropy"],
}
grid_search = RandomizedSearchCV(
data_model_pipeline,
hyperparameters,
cv=5,
scoring=score,
n_jobs=8,
)
grid_search.fit(x_train, y_train);
grid_search.best_params_
{'model__max_features': 7,
'model__max_depth': 4,
'model__criterion': 'entropy'}
best_data_model_pipeline = grid_search.best_estimator_
Evaluation
y_pred = best_data_model_pipeline.predict(x_test)
recall = recall_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
auc = roc_auc_score(y_test, y_pred)
print(f"recall: {recall}")
print(f"precision: {precision}")
print(f"f1: {f1}")
print(f"auc: {auc}")
recall: 0.73
precision: 0.8390804597701149
f1: 0.7807486631016043
auc: 0.8217901234567903
Model Validation
train_ds = Dataset(
pd.concat([x_train, y_train], axis="columns"),
label=target,
cat_features=cols_categorical,
set_index_from_dataframe_index=True,
)
test_ds = Dataset(
pd.concat([x_test, y_test], axis="columns"),
label=target,
cat_features=cols_categorical,
set_index_from_dataframe_index=True,
)
evaluation_suite = model_evaluation()
suite_result = evaluation_suite.run(train_ds, test_ds, best_data_model_pipeline)
# Note: the result can be saved as html using suite_result.save_as_html()
# or exported to json using suite_result.to_json()
suite_result.show_not_interactive()
deepchecks - WARNING - Cannot use model's built-in feature importance on a Scikit-learn Pipeline, using permutation feature importance calculation instead
deepchecks - INFO - Calculating permutation feature importance. Expected to finish in 9 seconds
Model Evaluation Suite
The suite is composed of various checks such as: Confusion Matrix Report, Boosting Overfit, Calibration Score, etc...
Each check may contain conditions (which will result in pass ✓ /
fail ✖ / warning ! / error ⁈) as well as
other outputs such as plots or tables.
Suites, checks and conditions can all be modified. Read more about
custom suites.
Conditions Summary
Status | Check | Condition | More Info |
---|---|---|---|
! | Weak Segments Performance - Train Dataset | The relative performance of weakest segment is greater than 80% of average model performance. | Found a segment with accuracy score of 0.605 in comparison to an average score of 0.815 in sampled data. |
! | Weak Segments Performance - Test Dataset | The relative performance of weakest segment is greater than 80% of average model performance. | Found a segment with accuracy score of 0.667 in comparison to an average score of 0.844 in sampled data. |
✓ | Train Test Performance | Train-Test scores relative degradation is less than 0.1 | Found max degradation of -2.17% for metric Precision and class 0. |
✓ | ROC Report - Train Dataset | AUC score for all the classes is greater than 0.7 | All classes passed, minimum AUC found is 0.88 for class 1 |
✓ | ROC Report - Test Dataset | AUC score for all the classes is greater than 0.7 | All classes passed, minimum AUC found is 0.89 for class 1 |
✓ | Prediction Drift | Prediction drift score < 0.15 | Found model prediction Kolmogorov-Smirnov drift score of 0.08 |
✓ | Simple Model Comparison | Model performance gain over simple model is greater than 10% | All classes passed, average gain for metrics: {'F1': '63.25%'} |
✓ | Unused Features - Train Dataset | Number of high variance unused features is less or equal to 5 | Found 4 high variance unused features |
✓ | Unused Features - Test Dataset | Number of high variance unused features is less or equal to 5 | Found 4 high variance unused features |
✓ | Model Inference Time - Train Dataset | Average model inference time for one sample is less than 0.001 | Found average inference time (seconds): 2.176e-05 |
✓ | Model Inference Time - Test Dataset | Average model inference time for one sample is less than 0.001 | Found average inference time (seconds): 6.873e-05 |
Check With Conditions Output
Weak Segments Performance - Train Dataset
Search for segments with low performance scores. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
! | The relative performance of weakest segment is greater than 80% of average model performance. | Found a segment with accuracy score of 0.605 in comparison to an average score of 0.815 in sampled data. |
Additional Outputs
The full list of weak segments can be observed in the check result value.
sex vs fare
sex vs pclass
sex vs embarked
sex vs parch
sex vs sibsp
Weak Segments Performance - Test Dataset
Search for segments with low performance scores. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
! | The relative performance of weakest segment is greater than 80% of average model performance. | Found a segment with accuracy score of 0.667 in comparison to an average score of 0.844 in sampled data. |
Additional Outputs
The full list of weak segments can be observed in the check result value.
sex vs fare
pclass vs age
Train Test Performance
Summarize given model performance on the train and test datasets based on selected scorers. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Train-Test scores relative degradation is less than 0.1 | Found max degradation of -2.17% for metric Precision and class 0. |
Additional Outputs
ROC Report - Train Dataset
Calculate the ROC curve for each class. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | AUC score for all the classes is greater than 0.7 | All classes passed, minimum AUC found is 0.88 for class 1 |
Additional Outputs
ROC Report - Test Dataset
Calculate the ROC curve for each class. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | AUC score for all the classes is greater than 0.7 | All classes passed, minimum AUC found is 0.89 for class 1 |
Additional Outputs
Prediction Drift
Calculate prediction drift between train dataset and test dataset, using statistical measures. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Prediction drift score < 0.15 | Found model prediction Kolmogorov-Smirnov drift score of 0.08 |
Additional Outputs
The check shows the drift score and distributions for the predicted class probabilities.
Simple Model Comparison
Compare given model score to simple model score (according to given model type). Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Model performance gain over simple model is greater than 10% | All classes passed, average gain for metrics: {'F1': '63.25%'} |
Additional Outputs
Unused Features - Train Dataset
Detect features that are nearly unused by the model. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Number of high variance unused features is less or equal to 5 | Found 4 high variance unused features |
Additional Outputs
Unused Features - Test Dataset
Detect features that are nearly unused by the model. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Number of high variance unused features is less or equal to 5 | Found 4 high variance unused features |
Additional Outputs
Model Inference Time - Train Dataset
Measure model average inference time (in seconds) per sample. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Average model inference time for one sample is less than 0.001 | Found average inference time (seconds): 2.176e-05 |
Additional Outputs
Note - data sampling: Data is sampled from the original dataset, running on 1000 samples out of 1047. Sample size can be controlled with the "n_samples" parameter.
Model Inference Time - Test Dataset
Measure model average inference time (in seconds) per sample. Read More...
Conditions Summary
Status | Condition | More Info |
---|---|---|
✓ | Average model inference time for one sample is less than 0.001 | Found average inference time (seconds): 6.873e-05 |
Additional Outputs
Check Without Conditions Output
Confusion Matrix Report - Train Dataset
Calculate the confusion matrix of the model on the given dataset. Read More...
Additional Outputs
Best accuracy achieved on samples with 0 label (88.41%).
Worst accuracy achieved on samples with 1 label (70.25%).
Confusion Matrix Report - Test Dataset
Calculate the confusion matrix of the model on the given dataset. Read More...
Additional Outputs
Best accuracy achieved on samples with 0 label (91.36%).
Worst accuracy achieved on samples with 1 label (73.0%).
Calibration Metric - Train Dataset
Calculate the calibration curve with brier score for each class. Read More...
Additional Outputs
Calibration Metric - Test Dataset
Calculate the calibration curve with brier score for each class. Read More...
Additional Outputs
Other Checks That Weren't Displayed
Check | Reason |
---|---|
Regression Error Distribution - Train Dataset | Check is irrelevant for classification tasks |
Regression Error Distribution - Test Dataset | Check is irrelevant for classification tasks |
Boosting Overfit | Check is relevant for Boosting models of type ('AdaBoostClassifier', 'GradientBoostingClassifier', 'LGBMClassifier', 'XGBClassifier', 'CatBoostClassifier', 'AdaBoostRegressor', 'GradientBoostingRegressor', 'LGBMRegressor', 'XGBRegressor', 'CatBoostRegressor'), but received model of type RandomForestClassifier |
Save the model
# Save the model with joblib
dump(
best_data_model_pipeline,
"model.joblib",
protocol=5,
)
['model.joblib']
Analisis de Resultados
El análisis de los resultados muestra una mezcla de hallazgos positivos y áreas de mejora. Si bien el modelo supera a los modelos de referencia basicos y utiliza las características de los datos de entrenamiento de manera efectiva, existen problemas notables identificados. El chequeo de “Train Test Performance” indica que el modelo tuvo una degradación relativa en la métrica de Precisión al pasar de los datos de entrenamiento a los de prueba, sugiriendo un posible sobreajuste. Además, el chequeo de “Weak Segments Performance” identificó segmentos específicos de datos en el conjunto de prueba donde el rendimiento del modelo (medido por la precisión) fue significativamente menor que el rendimiento promedio, lo que requiere una investigación más profunda. La suite proporciona resultados detallados para cada chequeo, permitiendo una exploración a fondo del comportamiento del modelo.
A continuación, se explican los resultados de cada uno de los checks de la suite de evaluación del modelo:
- Train Test Performance: Este chequeo compara el rendimiento del modelo en los conjuntos de entrenamiento y prueba. El resultado en el documento es fallido (✖) porque la degradación relativa de las puntuaciones de entrenamiento a prueba fue mayor que el umbral permitido (0.1). Específicamente, se encontró una degradación máxima del 14.86% para la métrica Precisión en la clase 1, indicando un posible sobreajuste donde el modelo funciona notablemente peor en datos no vistos en comparación con los datos de entrenamiento.
- Weak Segments Performance - Test Dataset: Este chequeo busca segmentos de datos en el conjunto de prueba donde el modelo tiene un rendimiento bajo. El resultado es una advertencia (!). Se identificó un segmento con una puntuación de precisión del 0.571, en comparación con la puntuación promedio del modelo de 0.832 en los datos muestreados. Esto resalta áreas específicas (ej. intersecciones de características como sexo vs tarifa, sexo vs pclass, etc.) donde el modelo no generaliza bien.
- ROC Report - Train Dataset: Este chequeo calcula la curva ROC y el área bajo la curva (AUC) para cada clase en el conjunto de entrenamiento. El resultado es aprobado (✓) porque la puntuación AUC para todas las clases fue mayor que el umbral (0.7). El AUC mínimo encontrado fue de 0.97 para la clase 1, lo que indica un excelente rendimiento en el conjunto de entrenamiento.
- ROC Report - Test Dataset: Similar al anterior, pero evalúa el rendimiento ROC en el conjunto de prueba. El resultado es aprobado (✓). La puntuación AUC para todas las clases fue mayor que 0.7, con un AUC mínimo de 0.89 para la clase 1. Esto muestra un buen rendimiento del modelo en datos no vistos en términos de capacidad para distinguir entre clases.
- Prediction Drift: Este chequeo calcula la deriva en las predicciones del modelo entre los conjuntos de entrenamiento y prueba utilizando medidas estadísticas como la de Kolmogorov-Smirnov. El resultado es aprobado (✓). La puntuación de deriva encontrada fue de 0.11, la cual está por debajo del umbral permitido (0.15). Esto sugiere que la distribución de las predicciones del modelo es similar en ambos conjuntos de datos.
- Simple Model Comparison: Este chequeo compara la puntuación de rendimiento del modelo actual con la de modelos base simples (ingenuos). El resultado es aprobado (✓). Se encontró que el modelo tiene una ganancia de rendimiento (medida por F1) de más del 10% sobre el modelo simple para todas las clases (específicamente, un 60.39% de ganancia promedio en F1). Esto indica que el modelo aprende patrones significativos en los datos y no se desempeña peor que una línea base trivial.
- Weak Segments Performance - Train Dataset: Similar al chequeo para el conjunto de prueba, pero evalúa el rendimiento en segmentos de datos del conjunto de entrenamiento. El resultado es aprobado (✓). Aunque se encontraron segmentos con rendimiento relativamente más bajo, su precisión aún superó el 80% del rendimiento promedio del modelo en los datos muestreados (0.869 vs 0.91).
- Unused Features - Test Dataset: Este chequeo detecta características en el conjunto de prueba que el modelo casi no utiliza. El resultado es aprobado (✓). Se encontraron 4 características no utilizadas de alta varianza, lo cual está por debajo o igual al umbral permitido (5). Esto implica que el modelo está haciendo un buen uso de la mayoría de las características disponibles.
- Model Inference Time - Train Dataset y Model Inference Time - Test Dataset: Estos chequeos miden el tiempo promedio de inferencia por muestra en los conjuntos de entrenamiento y prueba, respectivamente. Ambos resultados son aprobados (✓). El tiempo promedio encontrado (2.469e-05 segundos) es significativamente menor que el umbral (0.001 segundos), lo que sugiere que el modelo es rápido para hacer predicciones.
- Confusion Matrix Report - Test Dataset: Este chequeo calcula y muestra la matriz de confusión del modelo en el conjunto de prueba. Aunque no tiene una condición de Pass/Fail/Warning listada en el resumen, proporciona la precisión global del modelo (81.63%) y la precisión por clase (88.27% para la clase 0, 75.0% para la clase 1).
- Calibration Metric - Train Dataset y Calibration Metric - Test Dataset: Estos chequeos calculan la curva de calibración y la puntuación Brier para evaluar qué tan bien calibradas están las predicciones probabilísticas del modelo en los conjuntos de entrenamiento y prueba. Al igual que el reporte de la matriz de confusión, no tienen una condición específica listada en el resumen, pero proporcionan gráficos y la puntuación Brier (aunque la puntuación Brier no se muestra explícitamente en el texto, la descripción indica que se calcula) para evaluar la calibración del modelo.
- Regression Error Distribution - Train Dataset y Regression Error Distribution - Test Dataset: Estos chequeos no se mostraron en los resultados porque son irrelevantes para tareas de clasificación, ya que el modelo utilizado es un clasificador.
- Boosting Overfit: Este chequeo no se mostró en los resultados porque es relevante solo para modelos de tipo Boosting, y el modelo utilizado (RandomForestClassifier) no es de este tipo.
Conclusiones
En base al análisis de los resultados, se obtienen varias conclusiones importantes. Por un lado, el modelo muestra un rendimiento prometedor en general, superando a los modelos base básicos y demostrando una buena capacidad para distinguir clases en datos no vistos (AUC). No obstante, la suite de evaluación ha identificado problemas cruciales que requieren atención.
Principalmente, la falla del chequeo “Train Test Performance” evidencia un sobreajuste (overfitting) del modelo al conjunto de entrenamiento, manifestado en una degradación notable de la métrica de Precisión en los datos de prueba. Esto significa que el modelo no generaliza tan bien como debería a nuevos datos, lo cual es un riesgo para su fiabilidad en producción. Además, la advertencia del chequeo “Weak Segments Performance - Test Dataset” señala segmentos específicos de datos donde el rendimiento es significativamente inferior, confirmando que el modelo tiene dificultades con ciertas subpoblaciones de datos.
Aunque otros checks pasaron (como el de Unused Features o Prediction Drift), estos hallazgos de sobreajuste y rendimiento débil en segmentos indican que el modelo necesita ajustes y reevaluación antes de ser considerado apto para su implementación en un entorno real.
📖 References
- https://docs.deepchecks.com/stable/tabular/auto_tutorials/quickstarts/plot_quick_model_evaluation.html
- https://joserzapata.github.io/courses/python-ciencia-datos/ml/
- https://joserzapata.github.io/courses/python-ciencia-datos/clasificacion/
- https://joserzapata.github.io/post/lista-proyecto-machine-learning/