Machine learning desde cero · Lección 2.5 · 12 de 33 lecciones listas · 12 min
Clases desequilibradas
En pocas palabras
Si una clase es rara, la exactitud esconde las pérdidas y el modelo aprende a decir «la clase común». Sensibilidad, exactitud equilibrada y pesos lo corrigen.
Calentamiento Dos preguntas de lecciones anteriores. Un minuto, y no bloquea la lección.
En la lección 1.3, «siempre benigno» tenía una exactitud alta y no detectaba a nadie. Allí la clase rara solo estaba en el test. Hoy es rara en los datos de aprendizaje, como en el cribado real, el fraude o las averías. Verás qué le hace eso al modelo, cómo medirlo y qué se puede arreglar sin datos nuevos.
Elige una respuesta y tu grado de seguridad.
Responde para desbloquear el experimento.
Experimento interactivo
Este experimento interactivo funciona en un navegador con JavaScript activado. El texto que lo rodea describe lo que muestra.
Ver la respuesta
Respuesta correcta: La sensibilidad, más de 20 puntos, y la exactitud solo unos 6 puntos
La sensibilidad cae del 83,0 % al 61,5 % (media de 5 sorteos de qué malignas se quedan), y la exactitud solo del 91,5 % al 85,6 %. En validación 89 de las 142 biopsias son benignas, y el modelo las reconoce cada vez con más seguridad, así que la exactitud apenas ve la pérdida.
Prueba esto
- Sin pesos, mueve el control de 159 a 8 malignas. ¿Qué línea cae más rápido: la sensibilidad o la exactitud?
- Con 8 malignas, activa los pesos de clase. ¿Cuánta sensibilidad vuelve y cuánta falta todavía frente a todos los datos?
- Mira la P(maligno) media predicha. ¿Cómo cambia cuando desaparecen malignas?
Cuando lo hayas comprobado en el lab, pongamos nombre a lo que ves.
La idea en pocas palabras
Las clases están desequilibradas cuando una es mucho más rara que la otra. El modelo aprende entonces dos cosas a la vez: cómo son las biopsias malignas y lo raras que son. Esa segunda lección funciona como un prejuicio: cuando las medidas no son claras, el modelo elige «benigno» cada vez más. La P(maligno) media predicha baja de 0,36 a 0,24 cuando quedan 8 malignas en el aprendizaje en lugar de 159.
La exactitud apenas lo ve. La sensibilidad cae del 83,0 % al 61,5 %, la exactitud solo del 91,5 % al 85,6 %. Por eso, con una clase rara, se informa de la sensibilidad de la clase rara o de la exactitud equilibrada, la media de las sensibilidades de las dos clases. «Siempre benigno» tiene una exactitud equilibrada de 0,5, sean cuales sean las proporciones.
La primera corrección es sencilla: los pesos de clase. Un error en la clase rara cuesta en el aprendizaje tantas veces más como veces es más rara esa clase (class_weight='balanced'). Con 8 malignas, los pesos suben la sensibilidad del 61,5 % al 80,0 %, y la exactitud incluso sube, al 91,4 %. Frente a todos los datos con pesos (86,8 %) todavía falta algo: los pesos cambian las proporciones, no añaden ejemplos.
Jak to policzono
- Biopsias: Breast Cancer Wisconsin (Diagnostic), UCI, licencia CC BY 4.0. 569 biopsias, 10 medidas «mean».
- Parte de validación: 25 % de las biopsias, estratificada (142: 53 malignas, 89 benignas), la misma en todos los ajustes. En el aprendizaje, 268 benignas y de 159 a 8 malignas; por debajo de 159 es la media de 5 sorteos de qué malignas se quedan.
- Modelo: estandarización con los datos de aprendizaje y regresión logística (C = 1), con o sin pesos de clase; umbral 0,5.
Por qué funciona
La regresión logística busca el modelo que menos se equivoca de media en los datos de aprendizaje. Con 268 benignas y 8 malignas, las malignas son solo el 2,9 % de la penalización total. El modelo mueve la frontera hacia el lado maligno: renuncia a unas cuantas malignas para fallar menos benignas. Los pesos de clase igualan la penalización: las 8 malignas juntas pesan lo mismo que las 268 benignas.
Una partición podría salir así por casualidad. En el código de abajo, el mismo experimento se repite con 50 particiones distintas: la sensibilidad cae de media del 89,3 % al 67,3 %, la exactitud del 93,5 % al 87,7 %, y los pesos con 8 malignas dan un 84,0 %. La sensibilidad cae más que la exactitud en 50 particiones de 50, y los pesos la suben en todas ellas.
La exactitud puede incluso subir sin que el modelo cambie nada. En el widget del Atlas sobre la exactitud equilibrada, un modelo débil con dos medidas puntúa las mismas biopsias mientras las malignas pasan de 212 a 20. Su exactitud sube del 75,9 % al 83,8 %, y la exactitud equilibrada no se mueve: 0,728 y 0,726. «Siempre benigno» con 20 malignas llega al 94,7 % de exactitud.
Error frecuente
Verdadero o falso: «SMOTE siempre ayuda». Falso. SMOTE fabrica ejemplos sintéticos de la clase rara en los segmentos entre ejemplos reales y sus vecinos más cercanos, hasta que las dos clases tienen el mismo tamaño. Eso mueve la frontera de decisión igual que los pesos de clase: el modelo dice «maligno» más a menudo. En el widget del Atlas sobre SMOTE (357 benignas, 30 malignas, dos medidas, validación cruzada 5 × 5), el modelo sin corrección detecta el 60,0 % de las malignas con una precisión del 90,0 %. SMOTE sube la detección al 86,7 %, pero la precisión cae al 42,9 %. Los pesos de clase dan la misma sensibilidad con una precisión del 40,2 %, y la simple duplicación con el 39,6 %. Es un sorteo de 30 malignas, el de mayor caída: de media en 20 sorteos la detección sube del 68,7 % al 91,9 % y la precisión cae del 91,0 % al 54,7 %. Cae en todos ellos. SMOTE no añade conocimiento, solo cambia las proporciones. Que eso ayude depende del coste de los errores: más detecciones a cambio de muchas falsas alarmas.
Un aviso: la corrección se aplica solo a los datos de aprendizaje. Ejemplos sintéticos o duplicados en la validación o el test darían un resultado que no significa nada.
Test
Tres preguntas para comprobar lo aprendido. Elige una respuesta o despliega la solución bajo cada pregunta. Con el teclado: las flechas eligen, Enter o Espacio confirma.
Ideas clave
- Cuando una clase es rara, la exactitud esconde las pérdidas: informa de la sensibilidad de la clase rara o de la exactitud equilibrada.
- El modelo también aprende las proporciones de las clases; con una clase rara en el aprendizaje elige la clase común cada vez más.
- Los pesos de clase y SMOTE mueven la frontera: más detecciones a cambio de falsas alarmas, sin conocimiento nuevo.
- Aplica las correcciones solo a los datos de aprendizaje y comprueba el resultado en una validación intacta, mejor con muchas particiones.
Más a fondo: fórmula, código, práctica
Las matemáticas
Exactitud = (TP + TN) / n, sensibilidad = TP / (TP + FN), especificidad = TN / (TN + FP), exactitud equilibrada = (sensibilidad + especificidad) / 2. «Siempre benigno» tiene sensibilidad 0 y especificidad 1, así que una exactitud equilibrada de (0 + 1) / 2 = 0,5.
La regresión logística minimiza la pérdida logística media L = Σᵢ wᵢ · ℓ(yᵢ, pᵢ) / Σᵢ wᵢ. Sin pesos wᵢ = 1, así que las 8 malignas son 8 / 276 ≈ 2,9 % de la pérdida total. Los pesos «balanced» son w = n / (2 · n_clase): 276 / 16 = 17,25 para una maligna y 276 / 536 ≈ 0,51 para una benigna, así que cada clase pesa en total n / 2 = 138.
En código (Python)
El mismo experimento en scikit-learn con 50 particiones distintas: todas las benignas y 159 u 8 malignas en el aprendizaje, con y sin pesos de clase, evaluado en la parte de validación intacta.
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import recall_score, accuracy_score
X, y = load_breast_cancer(return_X_y=True)
X, y = X[:, :10], 1 - y # las 10 medidas «mean», como en el lab; 1 = maligno
def run(seed, m, weights):
tr, va = train_test_split(np.arange(len(y)), test_size=0.25, stratify=y, random_state=seed)
mal = np.random.default_rng(seed).choice(tr[y[tr] == 1], m, replace=False)
keep = np.r_[tr[y[tr] == 0], mal] # todas las benignas + m malignas para aprender
clf = make_pipeline(StandardScaler(), LogisticRegression(class_weight="balanced" if weights else None))
pred = clf.fit(X[keep], y[keep]).predict(X[va]) # la parte de validación no cambia
return recall_score(y[va], pred), accuracy_score(y[va], pred)
for m, w in ((159, False), (8, False), (8, True)):
rec, acc = np.mean([run(s, m, w) for s in range(50)], axis=0)
print(f"{m} malignant{' + class weights' if w else ''}: recall {rec:.1%}, accuracy {acc:.1%} (mean of 50 splits)")
drop = np.array([np.subtract(run(s, 159, False), run(s, 8, False)) for s in range(50)])
gain = np.array([run(s, 8, True)[0] - run(s, 8, False)[0] for s in range(50)])
print(f"recall fell more than accuracy in {(drop[:, 0] > drop[:, 1]).sum()} of 50 splits; weights raised recall in {(gain > 0).sum()}")
Resultado
159 malignant: recall 89.3%, accuracy 93.5% (mean of 50 splits)
8 malignant: recall 67.3%, accuracy 87.7% (mean of 50 splits)
8 malignant + class weights: recall 84.0%, accuracy 91.0% (mean of 50 splits)
recall fell more than accuracy in 50 of 50 splits; weights raised recall in 50
El lab muestra una partición y 5 sorteos, el código 50 particiones, así que los números son distintos: en la partición del lab la sensibilidad con todos los datos es del 83,0 %, de media del 89,3 %. La conclusión es la misma en cada partición.
Descargar el notebook (.ipynb). Ábrelo en Jupyter o súbelo a Google Colab; descarga por sí solo los datos que falten.
Para profesionales
- En scikit-learn los pesos salen de
class_weight="balanced"(regresión logística, SVM, árboles, bosques) y la exactitud equilibrada debalanced_accuracy_score. Informa también de la sensibilidad y la precisión de la clase rara. - Divide con estratificación (
stratify=y,StratifiedKFold), para que la clase rara llegue a cada parte. - SMOTE y la duplicación están en la biblioteca imbalanced-learn. Úsalos dentro de su
Pipeline, para que actúen solo en las partes de aprendizaje de la validación cruzada. - Los pesos de clase y un umbral más bajo hacen algo parecido: mueven la decisión hacia la clase rara. El umbral lo puedes elegir en validación con la curva PR (lección 2.3), sin volver a entrenar el modelo.
¿Te ha sido útil?
¡Gracias! Nos ayuda a mejorar.
Profundiza en el Atlas
Entradas de la enciclopedia sobre las ideas de esta lección: