scikit-learn

ScikitLearn

Tutorial ScikitLearn: Preprocesamiento de datos desbalanceados

Scikit-Learn: Preprocesamiento de datos desbalanceados. Aprende a manejar datos desequilibrados en aprendizaje automático utilizando técnicas como SMOTE, ensamblados y evaluaciones especializadas.

Aprende ScikitLearn GRATIS y certifícate

Problemas causados por datos desbalanceados

En el aprendizaje automático, los datos desbalanceados son un desafío significativo que puede afectar negativamente el rendimiento de los modelos de clasificación. Un conjunto de datos está desbalanceado cuando las clases no se distribuyen de manera equitativa; es decir, una o varias clases tienen muchas más muestras que otras. Este desequilibrio puede conducir a modelos que están sesgados hacia las clases mayoritarias, ignorando las minoritarias.

Por ejemplo, en un problema de detección de fraude, las transacciones fraudulentas representan una fracción mínima del total. Si entrenamos un modelo sin abordar el desbalanceo, es probable que este prediga siempre la clase mayoritaria (no fraude), obteniendo aparentemente una alta precisión, pero fallando en identificar correctamente los casos de fraude.

Las consecuencias principales de trabajar con datos desbalanceados son:

  • Sesgo del modelo: El modelo aprende principalmente de la clase mayoritaria, lo que reduce su capacidad para generalizar y detectar correctamente las clases minoritarias.
  • Métricas de evaluación engañosas: Medidas como la precisión global pueden ser poco informativas. Es fundamental utilizar métricas como la matriz de confusión, recall, precision o F1-score que proporcionen una visión más detallada del rendimiento por clase.
  • Problemas en el criterio de parada: Algunos algoritmos pueden considerar que han convergido antes de tiempo si no se ajustan adecuadamente a la clase minoritaria.

En Scikit-Learn, si se utilizan modelos sin ajustar los parámetros correspondientes, estos pueden ser afectados por los datos desbalanceados. Algunos algoritmos ofrecen parámetros para manejar este problema. Por ejemplo:

  • En árboles de decisión y bosques aleatorios, podemos ajustar el parámetro class_weight='balanced' para penalizar las clases en función de su frecuencia.
  • Para máquinas de vectores de soporte (SVM), el parámetro class_weight también puede ser utilizado para equilibrar el impacto de las clases.
from sklearn.ensemble import RandomForestClassifier

# Crear un modelo con ajuste de pesos para clases desbalanceadas
modelo = RandomForestClassifier(class_weight='balanced')

Además, es importante analizar la distribución de clases antes de entrenar el modelo. Podemos utilizar la función value_counts() de Pandas para visualizar el desbalanceo:

import pandas as pd

# Supongamos que 'y' es nuestra variable objetivo
conteo_clases = y.value_counts()
print(conteo_clases)

Este análisis preliminar nos permite tomar decisiones informadas sobre cómo abordar el desbalanceo, ya sea mediante técnicas de sobremuestreo, submuestreo o ajustando los parámetros del modelo.

Otro problema derivado es la sobreajuste en la clase minoritaria si se utiliza sobremuestreo sin precaución. Al replicar excesivamente las muestras minoritarias, el modelo puede aprender detalles específicos del conjunto de entrenamiento que no generalizan bien a datos nuevos.

Es crucial también considerar la estratificación al dividir los datos en conjuntos de entrenamiento y prueba. Al utilizar train_test_split de Scikit-Learn, podemos asegurarnos de que la proporción de clases se mantiene en ambos conjuntos:

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)

La estratificación garantiza que ambas particiones representen adecuadamente la distribución original de las clases, lo cual es esencial para una evaluación justa del modelo.

En resumen, ignorar el desbalanceo de clases puede llevar a modelos ineficaces y conclusiones erróneas. Es fundamental reconocer estos problemas y aplicar técnicas adecuadas para mitigarlos, garantizando así un aprendizaje más robusto y equitativo.

Técnicas de sobremuestreo y submuestreo

En el preprocesamiento de datos desbalanceados, las técnicas de sobremuestreo y submuestreo son fundamentales para equilibrar la distribución de clases y mejorar el rendimiento de los modelos de aprendizaje automático. Estas técnicas ajustan el conjunto de datos, ya sea aumentando las muestras de la clase minoritaria o reduciendo las de la clase mayoritaria.

El sobremuestreo consiste en incrementar el número de muestras de la clase minoritaria. Una forma sencilla de hacerlo es mediante el sobremuestreo aleatorio, donde se duplican aleatoriamente las muestras existentes de la clase minoritaria hasta equilibrar las clases. Esto puede realizarse utilizando funciones básicas de Python o herramientas de Scikit-Learn.

Por otro lado, el submuestreo implica reducir el número de muestras de la clase mayoritaria. El submuestreo aleatorio elimina aleatoriamente muestras de la clase mayoritaria hasta alcanzar un equilibrio con la clase minoritaria. Aunque este método puede ser efectivo, existe el riesgo de perder información valiosa al descartar datos.

A continuación, se muestra cómo implementar el sobremuestreo aleatorio utilizando Scikit-Learn y NumPy:

import numpy as np
from sklearn.datasets import make_classification

# Crear un conjunto de datos desbalanceado
X, y = make_classification(n_samples=1000, n_features=20, 
                           n_classes=2, weights=[0.9, 0.1], 
                           random_state=42)

# Separar las clases mayoritaria y minoritaria
X_mayoritaria = X[y == 0]
X_minoritaria = X[y == 1]

# Número de muestras que necesitamos agregar a la clase minoritaria
n_muestras_a_agregar = len(X_mayoritaria) - len(X_minoritaria)

# Crear un generador aleatorio moderno con semilla
rng = np.random.default_rng(seed=42)

# Realizar sobremuestreo aleatorio
indices_aleatorios = rng.integers(0, len(X_minoritaria), size=n_muestras_a_agregar)
X_minoritaria_sobremuestreada = X_minoritaria[indices_aleatorios]
y_minoritaria_sobremuestreada = np.ones(n_muestras_a_agregar)

# Concatenar las muestras originales y sobremuestreadas
X_sobremuestreado = np.vstack((X, X_minoritaria_sobremuestreada))
y_sobremuestreado = np.hstack((y, y_minoritaria_sobremuestreada))

# Verificar las proporciones después del sobremuestreo
from collections import Counter
print("Distribución de clases después del sobremuestreo:", Counter(y_sobremuestreado))

En este ejemplo, hemos utilizado NumPy para duplicar aleatoriamente muestras de la clase minoritaria. El resultado es un conjunto de datos equilibrado que puede mejorar la capacidad del modelo para aprender las características de ambas clases.

El submuestreo aleatorio puede implementarse de manera similar, eliminando muestras de la clase mayoritaria:

from sklearn.utils import resample

# Separar las muestras de cada clase
X_mayoritaria = X[y == 0]
y_mayoritaria = y[y == 0]
X_minoritaria = X[y == 1]
y_minoritaria = y[y == 1]

# Submuestrear la clase mayoritaria
X_mayoritaria_submuestreada, y_mayoritaria_submuestreada = resample(
    X_mayoritaria, y_mayoritaria,
    replace=False,
    n_samples=len(X_minoritaria),
    random_state=42
)

# Combinar las clases submuestreadas
X_submuestreado = np.vstack((X_mayoritaria_submuestreada, X_minoritaria))
y_submuestreado = np.hstack((y_mayoritaria_submuestreada, y_minoritaria))

Aquí, hemos utilizado la función resample de Scikit-Learn para seleccionar aleatoriamente una muestra de la clase mayoritaria sin reemplazo. Esto crea un conjunto equilibrado pero reduce la cantidad total de datos disponibles para el entrenamiento.

Es importante considerar las implicaciones de cada técnica. El sobremuestreo aumenta el tamaño del conjunto de datos y puede llevar a sobreajuste si se duplican muchas muestras. El submuestreo reduce el tamaño del conjunto y puede provocar pérdida de información relevante de la clase mayoritaria.

Para abordar estas limitaciones, se pueden utilizar métodos más avanzados como el sobremuestreo sintético, que genera muestras artificiales de la clase minoritaria. Técnicas como SMOTE (Synthetic Minority Over-sampling Technique) crean nuevas muestras sintetizando características existentes. Aunque SMOTE no está incluido directamente en Scikit-Learn, es posible implementarlo o utilizar bibliotecas complementarias especializadas.

Además, es posible combinar ambas técnicas en métodos híbridos que aplican sobremuestreo a la clase minoritaria y submuestreo a la clase mayoritaria. Esto busca equilibrar el conjunto de datos sin los inconvenientes de cada técnica por separado.

Al integrar estas técnicas en el proceso de modelado, es esencial utilizar validación cruzada para evaluar adecuadamente el rendimiento y evitar sesgos. También es recomendable aplicar el sobremuestreo o submuestreo únicamente al conjunto de entrenamiento para no alterar la distribución real de los datos de prueba.

Por último, es crucial adaptar la técnica elegida al contexto específico del problema y al tipo de datos. No existe una solución universal, y la efectividad de cada método puede variar según el conjunto de datos y el modelo utilizado.

Algoritmos de sobremuestreo avanzados como SMOTE y variantes

En el contexto del aprendizaje automático, manejar datos desbalanceados es esencial para construir modelos eficaces. Los algoritmos de sobremuestreo avanzados como SMOTE (Synthetic Minority Over-sampling Technique) y sus variantes ofrecen soluciones sofisticadas para equilibrar las clases en datasets donde la clase minoritaria es significativamente menor que la mayoritaria.

SMOTE es una técnica que genera nuevas muestras sintéticas de la clase minoritaria en lugar de simplemente replicar ejemplos existentes. Esto se logra interpolando entre muestras cercanas en el espacio de características, lo que ayuda a que el modelo generalice mejor y no se sobreajuste a datos repetidos. En Scikit-Learn, SMOTE está integrado, facilitando su implementación en proyectos de aprendizaje supervisado.

Para utilizar SMOTE en Scikit-Learn, es necesario importar el módulo correspondiente y aplicarlo al conjunto de datos de entrenamiento:

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from imblearn.over_sampling import SMOTE
from sklearn.linear_model import LogisticRegression

# Generar un conjunto de datos desbalanceado
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2,
                           weights=[0.9, 0.1], random_state=42)

# Dividir en conjuntos de entrenamiento y prueba con estratificación
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y,
                                                    random_state=42)

# Aplicar escalado a los datos
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# Aplicar SMOTE al conjunto de entrenamiento
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)

# Entrenar un modelo de regresión logística
modelo = LogisticRegression()
modelo.fit(X_train_smote, y_train_smote)

En este ejemplo, se ha utilizado SMOTE para generar muestras sintéticas de la clase minoritaria antes de entrenar el modelo. Es importante destacar que el sobremuestreo debe aplicarse únicamente al conjunto de entrenamiento para evitar introducir sesgos en la evaluación del modelo.

Además de SMOTE, existen variantes que combinan técnicas de sobremuestreo y submuestreo, mejorando aún más el equilibrio de las clases y la calidad del modelo:

  • SMOTE Tomek Links: Combina SMOTE con la eliminación de Tomek Links, que son pares de muestras de clases opuestas muy cercanas entre sí. Esto ayuda a limpiar el ruido y definir mejor los límites entre clases.
  • SMOTE ENN (Edited Nearest Neighbours): Combina SMOTE con la eliminación de muestras mal clasificadas por sus vecinos más cercanos, refinando el espacio de características y eliminando posibles outliers.

Para implementar SMOTE Tomek Links en Scikit-Learn:

from imblearn.combine import SMOTETomek
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from collections import Counter

# Generar un conjunto de datos desbalanceado
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2,
                           weights=[0.9, 0.1], random_state=42)

# Dividir en conjuntos de entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)

# Aplicar SMOTE Tomek Links
smote_tomek = SMOTETomek(random_state=42)
X_train_st, y_train_st = smote_tomek.fit_resample(X_train, y_train)

# Verificar la nueva distribución de clases
print("Distribución de clases después de SMOTE Tomek Links:", Counter(y_train_st))

# Entrenar el modelo
modelo = LogisticRegression(random_state=42)
modelo.fit(X_train_st, y_train_st)

# Evaluar el modelo
y_pred = modelo.predict(X_test)
print(classification_report(y_test, y_pred))

La utilización de SMOTE ENN es similar:

from imblearn.combine import SMOTEENN
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

# Aplicar SMOTE ENN
smote_enn = SMOTEENN(random_state=42)
X_train_se, y_train_se = smote_enn.fit_resample(X_train, y_train)

# Verificar la nueva distribución de clases
print("Distribución de clases después de SMOTE ENN:", Counter(y_train_se))

# Entrenar el modelo
modelo = LogisticRegression(random_state=42)
modelo.fit(X_train_se, y_train_se)

# Evaluar el modelo
y_pred = modelo.predict(X_test)
print(classification_report(y_test, y_pred))

Al seleccionar entre SMOTE y sus variantes, es crucial considerar las características específicas del conjunto de datos y el comportamiento del modelo. Las variantes que combinan sobremuestreo y submuestreo pueden ser más efectivas en situaciones donde existen outliers o ruido en las clases.

Una palabra clave en este contexto es la interpolación, que es el proceso mediante el cual SMOTE genera nuevas muestras sintéticas. La interpolación lineal entre un punto de la clase minoritaria y sus vecinos crea ejemplos realistas que enriquecen el modelo sin duplicar datos existentes.

Es relevante también mencionar que, al utilizar estas técnicas avanzadas, las métricas de evaluación del modelo pueden mostrar mejoras significativas en la detección de la clase minoritaria. Sin embargo, es fundamental realizar una validación cruzada adecuada y utilizar métricas como la curva ROC, el AUC o el F1-score, que reflejan mejor el rendimiento en contextos desbalanceados.

Otro aspecto a considerar es el ajuste de los parámetros de SMOTE y sus variantes. Por ejemplo, el parámetro k_neighbors controla el número de vecinos utilizados para la interpolación:

smote = SMOTE(k_neighbors=5, random_state=42)

Ajustar este parámetro puede influir en la diversidad y representatividad de las muestras sintéticas generadas. Un valor adecuado de k_neighbors depende de la densidad de la clase minoritaria y debe ser seleccionado cuidadosamente.

En el caso de SMOTE Tomek Links y SMOTE ENN, los parámetros adicionales permiten controlar la estrategia de eliminación de muestras:

smote_tomek = SMOTETomek(tomek=TomekLinks(sampling_strategy='all'),
                         random_state=42)

La configuración de estos parámetros debe basarse en un análisis detallado de los datos y pruebas experimentales para encontrar la combinación óptima que mejore el rendimiento del modelo sin introducir sobreajuste.

Es importante tener en cuenta que, aunque SMOTE y sus variantes son herramientas poderosas, no sustituyen un buen entendimiento de los datos y una correcta ingeniería de características. La calidad de los datos sigue siendo un factor determinante en el éxito de cualquier modelo de aprendizaje automático.

Finalmente, la integración de estos algoritmos en pipelines de Scikit-Learn permite automatizar el proceso y garantizar que las transformaciones se apliquen de manera consistente:

from sklearn.pipeline import Pipeline

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('smote', SMOTE(random_state=42)),
    ('modelo', LogisticRegression())
], memory = None)

pipeline.fit(X_train, y_train)

Este enfoque asegura que el preprocesamiento, el sobremuestreo y el entrenamiento del modelo se realicen en secuencia, facilitando la reproducibilidad y mantenimiento del código.

En resumen, los algoritmos de sobremuestreo avanzados como SMOTE y sus variantes son herramientas esenciales para abordar el desafío de los datos desbalanceados. Su adecuada implementación en Scikit-Learn mejora significativamente la capacidad de los modelos para aprender de la clase minoritaria y ofrece un camino sólido hacia soluciones más equitativas y precisas en el aprendizaje supervisado.

Ensamblado de modelos para datos desbalanceados

El ensamblado de modelos es una estrategia eficaz para mejorar el rendimiento de los clasificadores en contextos de datos desbalanceados. Los modelos de ensamblado combinan múltiples estimadores de base para producir una predicción agregada, lo que puede aumentar la capacidad de generalización y mitigar el impacto del desbalance de clases.

Una técnica común es utilizar bosques aleatorios balanceados, donde se ajustan árboles de decisión sobre muestras bootstrap de los datos y se introducen modificaciones para abordar el desbalance. En Scikit-Learn, el parámetro class_weight='balanced' asigna automáticamente pesos inversamente proporcionales a la frecuencia de las clases, equilibrando su influencia en el entrenamiento.

from sklearn.ensemble import RandomForestClassifier

# Crear un bosque aleatorio balanceado
modelo_rf = RandomForestClassifier(class_weight='balanced', random_state=42)
modelo_rf.fit(X_train, y_train)

Otra aproximación es el submuestreo bajo bolsa (bagging), donde se aplican técnicas de submuestreo al crear las muestras bootstrap. El BalancedBaggingClassifier de la biblioteca imbalanced-learn permite combinar el ensamble por bolsa con submuestreo aleatorio, mejorando la detección de la clase minoritaria.

from imblearn.ensemble import BalancedBaggingClassifier
from sklearn.tree import DecisionTreeClassifier

# Crear un clasificador con submuestreo bajo bolsa
modelo_bbc = BalancedBaggingClassifier(
    base_estimator=DecisionTreeClassifier(),
    sampling_strategy='auto',
    replacement=False,
    random_state=42
)
modelo_bbc.fit(X_train, y_train)

Los métodos de ensamblado por boosting también pueden adaptarse a datos desbalanceados. El RUSBoostClassifier combina el resampling aleatorio por submuestreo con AdaBoost, reduciendo el impacto de la clase mayoritaria en cada iteración del entrenamiento.

from imblearn.ensemble import RUSBoostClassifier

# Crear un clasificador RUSBoost
modelo_rusboost = RUSBoostClassifier(
    base_estimator=DecisionTreeClassifier(max_depth=3),
    n_estimators=100,
    sampling_strategy='auto',
    random_state=42
)
modelo_rusboost.fit(X_train, y_train)

El EasyEnsembleClassifier es otro método que genera varios conjuntos submuestreados de la clase mayoritaria y entrena un clasificador en cada uno junto con la clase minoritaria completa. Las predicciones finales se obtienen mediante la agregación de los resultados individuales.

from imblearn.ensemble import EasyEnsembleClassifier

# Crear un clasificador EasyEnsemble
modelo_easy = EasyEnsembleClassifier(
    n_estimators=10,
    sampling_strategy='auto',
    random_state=42
)
modelo_easy.fit(X_train, y_train)

Es fundamental elegir el ensamblador adecuado según las características del problema y el conjunto de datos. Los parámetros como sampling_strategy permiten controlar la proporción de submuestreo o sobremuestreo aplicado en cada estimador base, ofreciendo flexibilidad para adaptar el modelo al desequilibrio presente.

La combinación de técnicas de ensamble con métodos de sobremuestreo como SMOTE puede mejorar aún más el rendimiento. Por ejemplo, el BalancedRandomForestClassifier implementa un bosque aleatorio donde cada árbol se entrena en una muestra aleatoria con submuestreo de la clase mayoritaria.

from imblearn.ensemble import BalancedRandomForestClassifier

# Crear un bosque aleatorio balanceado
modelo_brf = BalancedRandomForestClassifier(
    n_estimators=100,
    sampling_strategy='auto',
    random_state=42
)
modelo_brf.fit(X_train, y_train)

Al utilizar estos modelos, es imprescindible evaluar el rendimiento con métricas apropiadas para datos desbalanceados, como el recall, el F1-score o la curva ROC. De esta manera, se garantiza que el modelo no solo aprende a predecir la clase mayoritaria, sino que también es eficaz en la detección de la clase minoritaria.

El uso de pipelines en Scikit-Learn facilita la integración de estos ensambladores con técnicas de preprocesamiento y validación cruzada. Esto asegura un flujo de trabajo coherente y reproducible.

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

# Crear un pipeline con preprocesamiento y modelo
pipeline = make_pipeline(
    StandardScaler(),
    BalancedBaggingClassifier(
        base_estimator=DecisionTreeClassifier(),
        sampling_strategy='auto',
        random_state=42
    )
    memory = None 
)
pipeline.fit(X_train, y_train)

Los ensambladores permiten también ajustar los parámetros de los estimadores base para mejorar la adaptación a los datos desbalanceados. Por ejemplo, limitar la profundidad de los árboles o ajustar los criterios de división puede reducir el sobreajuste y mejorar la generalización.

Además, es posible combinar diferentes tipos de estimadores en un VotingClassifier para aprovechar las fortalezas de cada modelo. Aunque este enfoque no está específicamente diseñado para datos desbalanceados, la incorporación de modelos balanceados puede mejorar las predicciones.

from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC

# Crear un ensamble de votación con modelos balanceados
modelo_voting = VotingClassifier(
    estimadores=[
        ('lr', LogisticRegression(class_weight='balanced', random_state=42)),
        ('svc', SVC(kernel='linear', class_weight='balanced', probability=True, random_state=42)),
        ('dt', DecisionTreeClassifier(class_weight='balanced', random_state=42))
    ],
    voting='soft'
)
modelo_voting.fit(X_train, y_train)

En este ejemplo, se combinan diferentes algoritmos, cada uno ajustado para manejar el desbalance mediante el parámetro class_weight='balanced'. El voto suave (voting='soft') utiliza las probabilidades de predicción para promediar los resultados.

Es esencial realizar una validación cruzada estratificada al evaluar modelos en datos desbalanceados. Esto garantiza que la proporción de clases se mantiene en cada partición, proporcionando estimaciones más fiables del rendimiento.

from sklearn.model_selection import cross_val_score, StratifiedKFold

# Definir validación cruzada estratificada
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# Evaluar el modelo con validación cruzada
scores = cross_val_score(modelo_brf, X_train, y_train, cv=cv, scoring='f1')
print(f"Puntuaciones F1 por fold: {scores}")
print(f"Puntuación F1 media: {scores.mean():.3f}")

La selección cuidadosa de las métricas y métodos de evaluación es clave para desarrollar modelos robustos en presencia de clases desequilibradas. Los ensambladores ofrecen herramientas poderosas para abordar este desafío, permitiendo mejorar la capacidad predictiva y generalización de los modelos en contextos complejos.

Evaluación en contextos desbalanceados

La evaluación de modelos en conjuntos de datos desbalanceados presenta retos únicos que requieren un enfoque cuidadoso. En escenarios donde una clase es significativamente más numerosa que otra, las métricas de evaluación tradicionales pueden ofrecer una visión distorsionada del rendimiento real del modelo.

Una métrica común como la exactitud (accuracy) puede resultar engañosa en estos contextos. Por ejemplo, si una clase representa el 95% de los datos, un modelo que siempre predice esa clase alcanzará un 95% de exactitud, pero será inútil para identificar la clase minoritaria. Por ello, es esencial emplear métricas que reflejen el rendimiento en ambas clases.

La matriz de confusión es una herramienta fundamental que muestra el número de verdaderos positivos, falsos positivos, verdaderos negativos y falsos negativos. A partir de ella, se pueden calcular métricas más informativas:

1 .  Precisión (Precision): Proporción de verdaderos positivos entre todos los positivos predichos. Indica la exactitud de las predicciones positivas del modelo.

$$
\text{Precisión} = \frac{\text{Verdaderos Positivos}}{\text{Verdaderos Positivos} + \text{Falsos Positivos}}
$$

2.   Exhaustividad (Recall): Proporción de verdaderos positivos entre todos los positivos reales. Mide la capacidad del modelo para encontrar todos los casos positivos.

$$
\text{Exhaustividad} = \frac{\text{Verdaderos Positivos}}{\text{Verdaderos Positivos} + \text{Falsos Negativos}}
$$

3.   F1-score: Media armónica de la precisión y la exhaustividad. Equilibra ambas métricas en una sola.

$$
F1 = 2 \times \frac{\text{Precisión} \times \text{Exhaustividad}}{\text{Precisión} + \text{Exhaustividad}}
$$

En Scikit-Learn, estas métricas se pueden calcular fácilmente utilizando funciones específicas:

from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score

# Supongamos que y_test son las etiquetas verdaderas y y_pred son las predicciones del modelo
matriz_confusion = confusion_matrix(y_test, y_pred)
print("Matriz de Confusión:")
print(matriz_confusion)

precision = precision_score(y_test, y_pred)
exhaustividad = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)

print(f"Precisión: {precision:.2f}")
print(f"Exhaustividad: {exhaustividad:.2f}")
print(f"F1-score: {f1:.2f}")

Otra herramienta crucial es la curva ROC (Receiver Operating Characteristic) y el AUC (Area Under the Curve). La curva ROC representa la relación entre la tasa de verdaderos positivos y la tasa de falsos positivos a diferentes umbrales de clasificación. Un AUC cercano a 1 indica un modelo con excelente capacidad discriminativa.

from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt

# Calcular probabilidades de predicción
y_score = modelo.predict_proba(X_test)[:, 1]

# Obtener valores para la curva ROC
fpr, tpr, thresholds = roc_curve(y_test, y_score)
auc = roc_auc_score(y_test, y_score)

# Graficar la curva ROC
plt.figure()
plt.plot(fpr, tpr, label=f"Curva ROC (AUC = {auc:.2f})")
plt.plot([0, 1], [0, 1], linestyle='--', color='red')
plt.xlabel('Tasa de Falsos Positivos')
plt.ylabel('Tasa de Verdaderos Positivos')
plt.title('Curva ROC')
plt.legend()
plt.show()

En casos de desbalance extremo, la curva Precision-Recall puede ser más informativa. Esta curva muestra la relación entre la precisión y la exhaustividad para diferentes umbrales, resaltando el rendimiento del modelo en la detección de la clase minoritaria.

from sklearn.metrics import precision_recall_curve, average_precision_score

# Obtener valores para la curva Precision-Recall
precision, recall, thresholds = precision_recall_curve(y_test, y_score)
ap = average_precision_score(y_test, y_score)

# Graficar la curva Precision-Recall
plt.figure()
plt.plot(recall, precision, label=f"Curva Precision-Recall (AP = {ap:.2f})")
plt.xlabel('Exhaustividad')
plt.ylabel('Precisión')
plt.title('Curva Precision-Recall')
plt.legend()
plt.show()

Es importante utilizar validación cruzada estratificada para garantizar que la proporción de clases se mantiene en cada partición. Esto se logra con el parámetro StratifiedKFold de Scikit-Learn, que preserva la distribución original de las clases en cada fold.

from sklearn.model_selection import cross_val_score, StratifiedKFold

# Definir validación cruzada estratificada
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# Evaluar el modelo utilizando F1-score
scores = cross_val_score(modelo, X, y, cv=cv, scoring='f1')
print(f"Puntuaciones F1 por fold: {scores}")
print(f"Puntuación F1 media: {scores.mean():.2f}")

Otra palabra clave relevante es el ajuste de umbrales. En lugar de utilizar el umbral predeterminado de 0.5 para determinar las clases, es posible ajustarlo para equilibrar mejor la precisión y la exhaustividad según las necesidades específicas del problema.

# Ajustar el umbral de decisión
umbral = 0.3
y_pred_ajustado = (y_score >= umbral).astype(int)

# Recalcular métricas con el nuevo umbral
precision_ajustada = precision_score(y_test, y_pred_ajustado)
exhaustividad_ajustada = recall_score(y_test, y_pred_ajustado)
f1_ajustado = f1_score(y_test, y_pred_ajustado)

print(f"Precisión ajustada: {precision_ajustada:.2f}")
print(f"Exhaustividad ajustada: {exhaustividad_ajustada:.2f}")
print(f"F1-score ajustado: {f1_ajustado:.2f}")

El uso de la métrica Kappa de Cohen también puede ser útil, ya que mide el grado de concordancia entre las predicciones del modelo y las etiquetas reales, ajustando por concordancia aleatoria.

from sklearn.metrics import cohen_kappa_score

kappa = cohen_kappa_score(y_test, y_pred)
print(f"Kappa de Cohen: {kappa:.2f}")

Para una evaluación más completa, es recomendable utilizar el informe de clasificación que proporciona una visión general de múltiples métricas.

from sklearn.metrics import classification_report

reporte = classification_report(y_test, y_pred)
print("Informe de Clasificación:")
print(reporte)

En resumen, en contextos desbalanceados es crucial seleccionar métricas de evaluación que reflejen el rendimiento real del modelo en todas las clases. La utilización de herramientas como la curva ROC, el F1-score y la curva Precision-Recall permite una comprensión más profunda y precisa, facilitando la optimización y mejora continua del modelo.

Aprende ScikitLearn GRATIS online

Ejercicios de esta lección Preprocesamiento de datos desbalanceados

Evalúa tus conocimientos de esta lección Preprocesamiento de datos desbalanceados con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de ScikitLearn

Accede a todas las lecciones de ScikitLearn y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Aprendizaje Automático

scikit-learn

Introducción Y Entorno

Introducción E Instalación

scikit-learn

Introducción Y Entorno

Introducción Al Preprocesamiento De Datos

scikit-learn

Preprocesamiento De Datos

Identificación Y Tratamiento De Valores Faltantes

scikit-learn

Preprocesamiento De Datos

Escalado De Datos

scikit-learn

Preprocesamiento De Datos

Normalización De Datos

scikit-learn

Preprocesamiento De Datos

Codificación De Variables Categóricas

scikit-learn

Preprocesamiento De Datos

Ingeniería De Características

scikit-learn

Preprocesamiento De Datos

Selección De Características

scikit-learn

Preprocesamiento De Datos

Extracción De Características

scikit-learn

Preprocesamiento De Datos

Particionamiento De Datos

scikit-learn

Preprocesamiento De Datos

Preprocesamiento De Datos Desbalanceados

scikit-learn

Preprocesamiento De Datos

Introducción A La Regresión

scikit-learn

Regresión

Regresión Lineal

scikit-learn

Regresión

Regresión Knn Kneighborsregressor

scikit-learn

Regresión

Regresión Svm Con Svr

scikit-learn

Regresión

Regresión Con Árboles Decisiontreeregressor

scikit-learn

Regresión

Regresión Con Algoritmos De Conjunto

scikit-learn

Regresión

Introducción A La Clasificación

scikit-learn

Clasificación

Clasificación Con Regresión Logística

scikit-learn

Clasificación

Clasificación Knn Kneighborsclassifier

scikit-learn

Clasificación

Clasificación Svm Con Svc

scikit-learn

Clasificación

Clasificación Con Árboles Decisiontreeclassifier

scikit-learn

Clasificación

Clasificación Con Algoritmos De Conjunto

scikit-learn

Clasificación

Reducción De La Dimensionalidad Con Pca

scikit-learn

Aprendizaje No Supervisado

Clustering Con Kmeans

scikit-learn

Aprendizaje No Supervisado

Clustering Jerárquico

scikit-learn

Aprendizaje No Supervisado

Clustering De Densidad Con Dbscan

scikit-learn

Aprendizaje No Supervisado

Preprocesamiento De Textos Para Nlp

scikit-learn

Nlp

Representación De Texto Y Extracción De Características

scikit-learn

Nlp

Clasificación De Texto Con Scikit Learn

scikit-learn

Nlp

Análisis De Sentimiento

scikit-learn

Nlp

Técnicas Avanzadas De Extracción De Características

scikit-learn

Nlp

Introducción Al Análisis De Series Temporales

scikit-learn

Series Temporales

Preprocesamiento De Datos De Series Temporales

scikit-learn

Series Temporales

Ingeniería De Características Para Series Temporales

scikit-learn

Series Temporales

Transformación Y Escalado De Series Temporales

scikit-learn

Series Temporales

Validación Y Evaluación De Modelos En Series Temporales

scikit-learn

Series Temporales

Validación Y Evaluación De Modelos

scikit-learn

Validación De Modelos

Técnicas De Validación Cruzada

scikit-learn

Validación De Modelos

Métricas De Regresión

scikit-learn

Validación De Modelos

Métricas De Clasificación

scikit-learn

Validación De Modelos

Ajuste De Hiperparámetros

scikit-learn

Validación De Modelos

Introducción A Pipelines

scikit-learn

Pipelines Y Despliegue

Creación De Pipelines Básicos

scikit-learn

Pipelines Y Despliegue

Preprocesamiento De Datos Con Pipelines

scikit-learn

Pipelines Y Despliegue

Pipelines Y Validación Cruzada

scikit-learn

Pipelines Y Despliegue

Pipelines Con Columntransformer

scikit-learn

Pipelines Y Despliegue

Exportar E Importar Pipelines

scikit-learn

Pipelines Y Despliegue

Accede GRATIS a ScikitLearn y certifícate

Objetivos de aprendizaje de esta lección

  • Comprender los problemas causados por datos desbalanceados en modelos de aprendizaje automático.
  • Aplicar técnicas de sobremuestreo y submuestreo para equilibrar conjuntos de datos.
  • Implementar algoritmos avanzados de sobremuestreo como SMOTE y sus variantes en Scikit-Learn.
  • Utilizar estrategias de ensamblado de modelos para mejorar el rendimiento en contextos desbalanceados.
  • Evaluar modelos en situaciones de clases desequilibradas utilizando métricas apropiadas.