Menu
CoddyTech

Clases desequilibradas

Parte de la sección Aprendizaje supervisado del Journey de Machine Learning de Coddy. Lección 24 de 58.

Cuando 95 de cada 100 pacientes están sanos, un modelo que siempre dice «sano» obtiene una precisión del 95 % y no detecta a nadie. Con clases desequilibradas, la precisión da una impresión engañosa:

Barras de precisión y exhaustividad de tres modelos con datos en los que el 5 % de los pacientes están enfermos. Siempre sano: precisión 0.95, exhaustividad 0.00. Modelo simple: 0.98 y 0.62. Modelo equilibrado: 0.94 y 0.92

Dos soluciones. stratify=y mantiene la proporción de 95 a 5 en ambos conjuntos, así que el conjunto de prueba incluye pacientes enfermos que detectar. class_weight="balanced" hace que cada fila poco frecuente cuente más:

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=0, stratify=y)
model = LogisticRegression(max_iter=1000, class_weight="balanced")

El modelo equilibrado sacrifica un poco de precisión para detectar muchos más casos. En casos poco frecuentes, fíjate en la exhaustividad y la precisión, no en la exactitud.

challenge icon

Desafío

Intermedio

Aproximadamente el 5% de los rodamientos de una fábrica fallan antes de tiempo. El código inicial divide los registros de un banco de pruebas y evalúa un modelo simple, pero su conjunto de prueba contiene solo 2 rodamientos defectuosos, así que su valor de 0.993 significa poco.

  1. Corrige la división para que ambos conjuntos mantengan la misma proporción de rodamientos defectuosos.
  2. Entrena un segundo modelo que dé más peso a las filas defectuosas e imprime su línea como se muestra abajo.

Para otro banco:

Faulty bearings: train 8.1%, test 7.8%
Plain: accuracy 0.947, recall 0.417
Balanced: accuracy 0.900, recall 0.833

Pruébalo tú mismo

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, recall_score

# Una fila por rodamiento del banco de pruebas: 1 en faulty significa que falló poco después
parts = pd.read_csv("bearings.csv")
features = ["vibration_mm_s", "temp_c", "noise_db", "hours_k"]
X = parts[features]
y = parts["faulty"]

# Corrige esta división
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
print(f"Faulty bearings: train {y_train.mean() * 100:.1f}%, test {y_test.mean() * 100:.1f}%")

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

plain = LogisticRegression(max_iter=1000)
plain.fit(X_train, y_train)
pred = plain.predict(X_test)
print(f"Plain: accuracy {accuracy_score(y_test, pred):.3f}, recall {recall_score(y_test, pred):.3f}")

# Escribe tu código a continuación
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Aprendizaje supervisado

Practica por tu cuenta: Compilador de Python online