Validacion de Modelo

Por Jose R. Zapata

Ultima actualización: 24/May/2025

Invítame a un Café

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

StatusCheckConditionMore Info
!
Weak Segments Performance - Train DatasetThe 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 DatasetThe 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 PerformanceTrain-Test scores relative degradation is less than 0.1Found max degradation of -2.17% for metric Precision and class 0.
ROC Report - Train DatasetAUC score for all the classes is greater than 0.7All classes passed, minimum AUC found is 0.88 for class 1
ROC Report - Test DatasetAUC score for all the classes is greater than 0.7All classes passed, minimum AUC found is 0.89 for class 1
Prediction DriftPrediction drift score < 0.15Found model prediction Kolmogorov-Smirnov drift score of 0.08
Simple Model ComparisonModel performance gain over simple model is greater than 10%All classes passed, average gain for metrics: {'F1': '63.25%'}
Unused Features - Train DatasetNumber of high variance unused features is less or equal to 5Found 4 high variance unused features
Unused Features - Test DatasetNumber of high variance unused features is less or equal to 5Found 4 high variance unused features
Model Inference Time - Train DatasetAverage model inference time for one sample is less than 0.001Found average inference time (seconds): 2.176e-05
Model Inference Time - Test DatasetAverage model inference time for one sample is less than 0.001Found 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
StatusConditionMore 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
Showcasing intersections of features with weakest detected segments.
The full list of weak segments can be observed in the check result value.
sex vs fare

jpeg

Check ran on 1047 data samples. Accuracy Score on the full data set is 0.81.
sex vs pclass

jpeg

Check ran on 1047 data samples. Accuracy Score on the full data set is 0.81.
sex vs embarked

jpeg

Check ran on 1047 data samples. Accuracy Score on the full data set is 0.81.
sex vs parch

jpeg

Check ran on 1047 data samples. Accuracy Score on the full data set is 0.81.
sex vs sibsp

jpeg

Check ran on 1047 data samples. Accuracy Score on the full data set is 0.81.


Go to top


Weak Segments Performance - Test Dataset

Search for segments with low performance scores. Read More...

Conditions Summary
StatusConditionMore 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
Showcasing intersections of features with weakest detected segments.
The full list of weak segments can be observed in the check result value.
sex vs fare

jpeg

Check ran on 262 data samples. Accuracy Score on the full data set is 0.84.
pclass vs age

jpeg

Check ran on 262 data samples. Accuracy Score on the full data set is 0.84.


Go to top


Train Test Performance

Summarize given model performance on the train and test datasets based on selected scorers. Read More...

Conditions Summary
StatusConditionMore Info
Train-Test scores relative degradation is less than 0.1Found max degradation of -2.17% for metric Precision and class 0.
Additional Outputs

jpeg


Go to top


ROC Report - Train Dataset

Calculate the ROC curve for each class. Read More...

Conditions Summary
StatusConditionMore Info
AUC score for all the classes is greater than 0.7All classes passed, minimum AUC found is 0.88 for class 1
Additional Outputs

jpeg

The marked points are the optimal probability threshold cut-off points to predict said class. In plain terms, it is optimal to set the prediction rule such that if for some class the predicted probability is above the threshold of that class, then the prediction should be that class. They optimal thresholds are determined using Youden's index defined as sensitivity + specificity - 1.


Go to top


ROC Report - Test Dataset

Calculate the ROC curve for each class. Read More...

Conditions Summary
StatusConditionMore Info
AUC score for all the classes is greater than 0.7All classes passed, minimum AUC found is 0.89 for class 1
Additional Outputs

jpeg

The marked points are the optimal probability threshold cut-off points to predict said class. In plain terms, it is optimal to set the prediction rule such that if for some class the predicted probability is above the threshold of that class, then the prediction should be that class. They optimal thresholds are determined using Youden's index defined as sensitivity + specificity - 1.


Go to top


Prediction Drift

Calculate prediction drift between train dataset and test dataset, using statistical measures. Read More...

Conditions Summary
StatusConditionMore Info
Prediction drift score < 0.15Found model prediction Kolmogorov-Smirnov drift score of 0.08
Additional Outputs
The Drift score is a measure for the difference between two distributions, in this check - the test and train distributions.
The check shows the drift score and distributions for the predicted class probabilities.
For discrete distribution plots, showing the top 10 categories with largest difference between train and test.

jpeg


Go to top


Simple Model Comparison

Compare given model score to simple model score (according to given model type). Read More...

Conditions Summary
StatusConditionMore Info
Model performance gain over simple model is greater than 10%All classes passed, average gain for metrics: {'F1': '63.25%'}
Additional Outputs

jpeg


Go to top


Unused Features - Train Dataset

Detect features that are nearly unused by the model. Read More...

Conditions Summary
StatusConditionMore Info
Number of high variance unused features is less or equal to 5Found 4 high variance unused features
Additional Outputs
Features above the line are a sample of the most important features, while the features below the line are the unused features with highest variance, as defined by check parameters

jpeg


Go to top


Unused Features - Test Dataset

Detect features that are nearly unused by the model. Read More...

Conditions Summary
StatusConditionMore Info
Number of high variance unused features is less or equal to 5Found 4 high variance unused features
Additional Outputs
Features above the line are a sample of the most important features, while the features below the line are the unused features with highest variance, as defined by check parameters

jpeg


Go to top


Model Inference Time - Train Dataset

Measure model average inference time (in seconds) per sample. Read More...

Conditions Summary
StatusConditionMore Info
Average model inference time for one sample is less than 0.001Found average inference time (seconds): 2.176e-05
Additional Outputs
Average model inference time for one sample (in seconds): 2.176e-05

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.


Go to top


Model Inference Time - Test Dataset

Measure model average inference time (in seconds) per sample. Read More...

Conditions Summary
StatusConditionMore Info
Average model inference time for one sample is less than 0.001Found average inference time (seconds): 6.873e-05
Additional Outputs
Average model inference time for one sample (in seconds): 6.873e-05


Go to top


Check Without Conditions Output

Confusion Matrix Report - Train Dataset

Calculate the confusion matrix of the model on the given dataset. Read More...

Additional Outputs
The overall accuracy of your model is: 79.33%.
Best accuracy achieved on samples with 0 label (88.41%).
Worst accuracy achieved on samples with 1 label (70.25%).

jpeg


Go to top


Confusion Matrix Report - Test Dataset

Calculate the confusion matrix of the model on the given dataset. Read More...

Additional Outputs
The overall accuracy of your model is: 82.18%.
Best accuracy achieved on samples with 0 label (91.36%).
Worst accuracy achieved on samples with 1 label (73.0%).

jpeg


Go to top


Calibration Metric - Train Dataset

Calculate the calibration curve with brier score for each class. Read More...

Additional Outputs
Calibration curves (also known as reliability diagrams) compare how well the probabilistic predictions of a binary classifier are calibrated. It plots the true frequency of the positive label against its predicted probability, for binned predictions.

jpeg

The Brier score metric may be used to assess how well a classifier is calibrated. For more info, please visit https://en.wikipedia.org/wiki/Brier_score


Go to top


Calibration Metric - Test Dataset

Calculate the calibration curve with brier score for each class. Read More...

Additional Outputs
Calibration curves (also known as reliability diagrams) compare how well the probabilistic predictions of a binary classifier are calibrated. It plots the true frequency of the positive label against its predicted probability, for binned predictions.

jpeg

The Brier score metric may be used to assess how well a classifier is calibrated. For more info, please visit https://en.wikipedia.org/wiki/Brier_score


Go to top


Other Checks That Weren't Displayed

CheckReason
Regression Error Distribution - Train DatasetCheck is irrelevant for classification tasks
Regression Error Distribution - Test DatasetCheck is irrelevant for classification tasks
Boosting OverfitCheck is relevant for Boosting models of type ('AdaBoostClassifier', 'GradientBoostingClassifier', 'LGBMClassifier', 'XGBClassifier', 'CatBoostClassifier', 'AdaBoostRegressor', 'GradientBoostingRegressor', 'LGBMRegressor', 'XGBRegressor', 'CatBoostRegressor'), but received model of type RandomForestClassifier


Go to top

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

Jose R. Zapata