Existen dos grandes causas de error en los modelos de machine learning:
- El sesgo describe un modelo que hace suposiciones simplificadas para que la función objetivo sea más fácil de aproximar; por ejemplo, que todo hombre de 1,75 m viste una talla M: claramente sesgado.
- La varianza describe la variabilidad en la predicción del modelo; es decir, cuánto cambia la predicción del modelo cuando cambiamos los datos usados para entrenarlo.
Para lograr una solución más precisa, buscamos reducir la cantidad de sesgo y varianza presentes en el modelo. No es una tarea trivial. Sesgo y varianza están enfrentados: reducir uno aumenta el otro debido a un concepto conocido como el compromiso sesgo-varianza.
En este artículo aprenderás:
- Cómo detectar si un modelo sufre de alto sesgo o alta varianza
- Cómo diagnosticar un modelo con cualquiera de estos síntomas
- Cómo construir un modelo con buen ajuste
Antes de entrar a detectar los síntomas de error, profundicemos en el compromiso sesgo-varianza.
Una mirada al compromiso sesgo-varianza
Todos los algoritmos de aprendizaje supervisado persiguen el mismo objetivo: estimar la función de mapeo (f_hat) para una variable objetivo (y) dada cierta información de entrada (X). Nos referimos a la función que un modelo de machine learning intenta aproximar como la función objetivo.
Cambiar los datos de entrada usados para aproximar la variable objetivo probablemente dará lugar a una función objetivo distinta, lo que puede afectar las salidas que predice el modelo. Cuánto varía nuestra función objetivo a medida que cambia el conjunto de entrenamiento se conoce como la varianza. No queremos que el modelo tenga alta varianza porque, aunque el algoritmo pueda rendir de forma impecable durante el entrenamiento, fallará al generalizar a instancias no vistas.

En la imagen anterior, la función objetivo aproximada es la línea verde y la recta de mejor ajuste es la negra. Observa lo bien que el modelo aprende los datos de entrenamiento con la línea verde. Hace todo lo posible por separar las observaciones rojas y azules. Si entrenáramos este modelo con nuevas observaciones, aprendería una función objetivo completamente nueva e intentaría repetir el mismo comportamiento.
Piensa en un escenario en el que usamos un método lineal como la regresión lineal para aproximar la función objetivo. Lo primero que hay que notar es que asume una relación lineal entre los datos de entrada y la variable que queremos predecir. Los fenómenos del mundo real son bastante más complejos. A cambio de perder flexibilidad, esta suposición sencilla hace que la función objetivo sea mucho más rápida de aprender y más fácil de interpretar. A este enfoque lo llamamos sesgo.

En la imagen superior, la línea roja representa la función objetivo aprendida. Muchas observaciones quedan lejos de los valores que predice el modelo.
Podemos reducir el sesgo haciendo el modelo más flexible, pero eso introduce varianza. Y al revés: podemos reducir la varianza simplificando el modelo, pero entonces introducimos sesgo. No hay forma de escapar de esta relación. La mejor alternativa es elegir y configurar un modelo que logre un equilibrio entre sesgo y varianza.

Debido a factores desconocidos que influyen en la función objetivo, siempre existirá algo de error en el modelo, conocido como error irreducible. Esto puede observarse en la imagen anterior fijándonos en la cantidad de error que aparece bajo el punto más bajo de la curva de error total. Para construir el modelo ideal, debemos encontrar un equilibrio entre sesgo y varianza que minimice el error total. Esto se ilustra con la línea de puntos denominada complejidad óptima del modelo.
Ahora ampliemos la idea de sesgo y varianza usando curvas de aprendizaje.
La anatomía de una curva de aprendizaje
Las curvas de aprendizaje son gráficos que muestran el rendimiento de un modelo a medida que aumenta el tamaño del conjunto de entrenamiento. Otra forma de uso es mostrar el rendimiento del modelo a lo largo de un periodo de tiempo definido. Normalmente se utilizan para diagnosticar algoritmos que aprenden de forma incremental a partir de los datos. Funcionan evaluando un modelo en los conjuntos de entrenamiento y validación y, después, representando el rendimiento medido.
Por ejemplo, imagina que hemos modelado la relación entre algunas entradas y salidas con un algoritmo de machine learning. Empezamos entrenando el modelo con una sola instancia y validando con cien instancias. ¿Qué crees que ocurrirá? Si has pensado que el modelo aprenderá a la perfección ese dato de entrenamiento, acertaste: no habría errores.
No es difícil modelar la relación de una única entrada con su salida; basta con memorizarla. Lo complicado llega al intentar hacer predicciones precisas cuando aparecen nuevas instancias. Como nuestro modelo aprendió tan bien los datos de entrenamiento, le costará muchísimo generalizar a datos que no ha visto. En consecuencia, tendrá un rendimiento pobre en el conjunto de validación. Esto significa que habrá una gran diferencia entre el desempeño del modelo en entrenamiento y en validación. A esta diferencia la llamamos error de generalización.
Si queremos que el algoritmo tenga opciones de mejorar sus predicciones en el conjunto de validación, necesitamos añadir más datos. Incorporar nuevas instancias al entrenamiento cambiará inevitablemente la función objetivo del modelo. Podemos monitorizar y representar cómo evoluciona el rendimiento del modelo a medida que crece el conjunto de entrenamiento, tanto en entrenamiento como en validación.
Esto implica que el gráfico mostrará dos resultados distintos:
- Curva de entrenamiento: la curva calculada con los datos de entrenamiento; indica qué tan bien está aprendiendo el modelo.
- Curva de validación: la curva calculada con los datos de validación; indica qué tan bien generaliza el modelo a instancias no vistas.
Estas curvas nos muestran cómo evoluciona el rendimiento del modelo a medida que crecen los datos; de ahí el nombre de curvas de aprendizaje.
Nota: El mismo proceso puede usarse para saber cómo aprende nuestro modelo a lo largo del tiempo. En lugar de monitorizar el progreso según aumenta el tamaño de los datos, monitorizamos cómo mejora con el paso del tiempo. Por ejemplo, si decides aprender un idioma, se podría evaluar tu dominio y asignarle una puntuación numérica para mostrar tu progreso a lo largo de 52 semanas.
Ya conoces la anatomía de una curva de aprendizaje; pongámosla en práctica con un conjunto de datos real para que lo veas de forma visual.
Caso de uso: predicción de valoraciones inmobiliarias
Usaremos el dataset: market historical data set of real estate valuation. Estos datos se recogieron en Sindian Dist., New Taipei, Taiwán y consisten en información histórica de mercado.
Nuestra tarea es predecir la valoración inmobiliaria a partir de las siguientes variables:
- X1 = fecha de la transacción (por ejemplo, 2013.250 = marzo de 2013, 2013.500 = junio de 2013, etc.)
- X2 = antigüedad de la vivienda (unidad: años)
- X3 = distancia a la estación de MRT más cercana (unidad: metros)
- X4 = número de tiendas de conveniencia en el área accesible a pie (entero)
- X5 = coordenada geográfica, latitud (unidad: grados)
- X6 = coordenada geográfica, longitud (unidad: grados)
La variable objetivo se define como:
- Y = precio de la vivienda por unidad de superficie (10.000 nuevos dólares taiwaneses/Ping; Ping es una unidad local, 1 Ping = 3,3 metros cuadrados)
Como el objetivo que predecimos es continuo, el problema requiere técnicas de regresión.
Empecemos echando un vistazo a los datos:
import pandas as pd
data = pd.read_excel("/content/gdrive/MyDrive/real_estate_valuation_data.xlsx")
print(data.info())
data.head()
>>>>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 414 entries, 0 to 413
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 No 414 non-null int64
1 X1 transaction date 414 non-null float64
2 X2 house age 414 non-null float64
3 X3 distance to the nearest MRT station 414 non-null float64
4 X4 number of convenience stores 414 non-null int64
5 X5 latitude 414 non-null float64
6 X6 longitude 414 non-null float64
7 Y house price of unit area 414 non-null float64
dtypes: float64(6), int64(2)
memory usage: 26.0 KB
None
No X1 transaction date X2 house age X3 distance to the nearest MRT station X4 number of convenience stores X5 latitude X6 longitude Y house price of unit area
0 1 2012.916667 32.0 84.87882 10 24.98298 121.54024 37.9
1 2 2012.916667 19.5 306.59470 9 24.98034 121.53951 42.2
2 3 2013.583333 13.3 561.98450 5 24.98746 121.54391 47.3
3 4 2013.500000 13.3 561.98450 5 24.98746 121.54391 54.8
4 5 2012.833333 5.0 390.56840 5 24.97937 121.54245 43.1
Hay una característica extra llamada No que no aparece referenciada en la documentación del dataset. Es posible que sea un índice, pero para simplificar vamos a eliminarla. Además, los nombres de las variables no coinciden con los de la documentación, así que vamos a limpiarlos.
# renombrar las columnas
renamed_columns = [col.split()[0] for col in data.columns]
renamed_columns_map = {data.columns[i]:renamed_columns[i] for i in range(len(data.columns))}
data.rename(renamed_columns_map, axis=1, inplace=True)
# eliminar la columna No
data.drop("No", axis=1, inplace=True)
print(data.head())
# separar variables y objetivo
features, target = data.columns[:-1], data.columns[-1]
X = data[features]
y = data[target]
Así queda el dataset final antes de separar variables y etiquetas objetivo:
X1 X2 X3 X4 X5 X6 Y
0 2012.916667 32.0 84.87882 10 24.98298 121.54024 37.9
1 2012.916667 19.5 306.59470 9 24.98034 121.53951 42.2
2 2013.583333 13.3 561.98450 5 24.98746 121.54391 47.3
3 2013.500000 13.3 561.98450 5 24.98746 121.54391 54.8
4 2012.833333 5.0 390.56840 5 24.97937 121.54245 43.1
Para ilustrar sesgo, varianza y un buen ajuste, construiremos tres modelos: un árbol de decisión para regresión, una máquina de vectores de soporte para regresión y un bosque aleatorio. Tras construirlos, representaremos sus curvas de aprendizaje y comentaremos algunas técnicas de diagnóstico.
Diagnóstico con curvas de aprendizaje
Las curvas de aprendizaje se interpretan analizando su forma. Una vez entendida su forma y dinámica, podemos usarlas para diagnosticar problemas en el comportamiento de un modelo de machine learning.
La función learning_curve() de Scikit-learn facilita monitorizar las puntuaciones de entrenamiento y validación, que es lo necesario para trazar una curva de aprendizaje.
Los parámetros que pasamos a learning_curve() son los siguientes:
- estimator: el modelo usado para aproximar la función objetivo
- X: los datos de entrada
- y: la variable objetivo
- cv: la estrategia de particionado para validación cruzada
- scoring: la métrica para evaluar el rendimiento del modelo
- train_sizes: los tamaños absolutos de ejemplos de entrenamiento que se usarán para generar la curva de aprendizaje; en nuestro caso, valores elegidos de forma arbitraria.
Modelo 1: árbol de decisión para regresión
Un modelo con alta varianza se considera sobreajustado. Aprende extremadamente bien los datos de entrenamiento y el ruido aleatorio, lo que produce un modelo que rinde muy bien en entrenamiento pero falla al generalizar a instancias no vistas. Observamos este comportamiento cuando el algoritmo es demasiado flexible para el problema o cuando el modelo se entrena durante demasiado tiempo.
Por ejemplo, el árbol de decisión para regresión es un algoritmo no lineal. Los algoritmos no lineales suelen tener bajo sesgo y alta varianza. Esto sugiere que cambios en el dataset provocarán grandes variaciones en la función objetivo.
Veamos la alta varianza con nuestro árbol de decisión:
from sklearn.model_selection import learning_curve
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
# sobreajuste
decision_tree = DecisionTreeRegressor()
train_sizes, train_scores, test_scores = learning_curve(
estimator=decision_tree,
X=X,
y=y,
cv=5,
scoring="neg_root_mean_squared_error",
train_sizes = [1, 75, 165, 270, 331]
)
train_mean = -train_scores.mean(axis=1)
test_mean = -test_scores.mean(axis=1)
plt.subplots(figsize=(10,8))
plt.plot(train_sizes, train_mean, label="train")
plt.plot(train_sizes, test_mean, label="validation")
plt.title("Learning Curve")
plt.xlabel("Training Set Size")
plt.ylabel("RMSE")
plt.legend(loc="best")
plt.show()

El modelo comete muy pocos errores cuando debe predecir instancias vistas en el entrenamiento, pero rinde mal con instancias nuevas a las que no ha estado expuesto. Puedes observar este comportamiento fijándote en lo grande que es el error de generalización entre la curva de entrenamiento y la de validación. Una posible solución es añadir más instancias al conjunto de entrenamiento, lo que introduce sesgo. Otra es añadir regularización al modelo (por ejemplo, limitar la profundidad máxima del árbol).
Modelo 2: Support Vector Machine
Un modelo con alto sesgo se considera infraajustado. Realiza suposiciones demasiado simples sobre los datos, lo que dificulta aprender los patrones subyacentes. El resultado es un modelo con alto error tanto en entrenamiento como en validación. Este comportamiento aparece cuando el modelo es demasiado simple para el problema o cuando no se entrena el tiempo suficiente.
Por ejemplo, la Support Vector Machine es un algoritmo lineal. Los algoritmos lineales suelen tener alto sesgo y baja varianza. Esto implica que se hacen más suposiciones sobre la forma de la función objetivo. Para introducir más sesgo en nuestro modelo, hemos añadido regularización ajustando el parámetro C.
Mostremos el alto sesgo con nuestra SVM:
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
# infraajuste
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
svm = SVR(C=0.25)
train_sizes, train_scores, test_scores = learning_curve(
estimator=svm,
X=X_scaled,
y=y,
cv=5,
scoring="neg_root_mean_squared_error",
train_sizes = [1, 75, 150, 270, 331]
)
train_mean = -train_scores.mean(axis=1)
test_mean = -test_scores.mean(axis=1)
plt.subplots(figsize=(10,8))
plt.plot(train_sizes, train_mean, label="train")
plt.plot(train_sizes, test_mean, label="validation")
plt.title("Learning Curve")
plt.xlabel("Training Set Size")
plt.ylabel("RMSE")
plt.legend(loc="best")
plt.show()

A medida que aumenta el tamaño del conjunto de entrenamiento, la brecha de generalización entre la curva de entrenamiento y la de validación se vuelve muy pequeña. Esto indica que añadir más ejemplos no mejorará el rendimiento. Una solución puede ser crear más variables o hacer el modelo más flexible para reducir el número de suposiciones.
Modelo 3: Random Forest Regressor
Un modelo con buen ajuste se sitúa en el punto intermedio entre un modelo infraajustado y uno sobreajustado. Puede que no sea tan bueno en entrenamiento como en el caso de sobreajuste, pero cometerá muchos menos errores ante instancias nuevas. Este comportamiento se observa cuando el error de entrenamiento aumenta hasta estabilizarse, mientras el error de validación disminuye hasta estabilizarse.
Para demostrarlo, usaremos un random forest, que es un conjunto (ensemble) de árboles de decisión. Es decir, el modelo también es no lineal, pero se añade sesgo creando varios modelos diversos y combinando sus predicciones.
Además, hemos incorporado más regularización fijando max_depth, que controla la profundidad máxima de cada árbol, en tres.
Veamos el código:
from sklearn.ensemble import RandomForestRegressor
# mejor
random_forest = RandomForestRegressor(max_depth=3)
train_sizes, train_scores, test_scores = learning_curve(
estimator=random_forest,
X=X,
y=y,
cv=5,
scoring="neg_root_mean_squared_error",
train_sizes = [1, 75, 150, 270, 331]
)
train_mean = -train_scores.mean(axis=1)
test_mean = -test_scores.mean(axis=1)
plt.subplots(figsize=(10,8))
plt.plot(train_sizes, train_mean, label="train")
plt.plot(train_sizes, test_mean, label="validation")
plt.title("Learning Curve")
plt.xlabel("Training Set Size")
plt.ylabel("RMSE")
plt.legend(loc="best")
plt.show()

Ahora vemos que hemos reducido el error en los datos de validación. Ha sido a costa de un rendimiento algo peor en entrenamiento, pero en conjunto es un modelo mejor.
El error de generalización es mucho menor y el número de errores es bajo. Además, ambas curvas se estabilizan a partir de un tamaño de entrenamiento cercano a 250, lo que sugiere que añadir más instancias quizá no mejore mucho más este modelo.
En resumen, el comportamiento de un modelo puede observarse con curvas de aprendizaje. El escenario ideal al construir modelos de machine learning es mantener el error lo más bajo posible. Dos factores que elevan el error son el sesgo y la varianza; lograr un equilibrio entre ambos se traduce en un modelo que rinde mejor.
