Aprendiendo mejores prácticas para la evaluación de modelos y el ajuste de hiperparámetros

 (Extraído de: [1] "Python Machine Learning - Capítulo 6")

      Uso de  k-fold cross-validation  (validación cruzada de k pliegues) para evaluar el rendimiento del modelo
    
     Uno de los pasos clave en la construcción de un modelo de aprendizaje automático es estimar su rendimiento en datos que el modelo no ha visto antes. Supongamos que ajustamos nuestro modelo en un conjunto de datos de entrenamiento y utilizamos los mismos datos para estimar su rendimiento en la práctica. Un modelo puede sufrir un subajuste (alto sesgo) si el modelo es demasiado simple, o puede sobreajustar los datos de entrenamiento (alta varianza) si el modelo es demasiado complejo para los datos de entrenamiento subyacentes. Para encontrar un equilibrio aceptable entre el sesgo y la varianza, tenemos que evaluar nuestro modelo cuidadosamente. A continuación, estudiaremos las técnicas holdout cross-validation (validación cruzada de retención) y  k-fold cross-validation (validación cruzada de k pliegues), que pueden ayudarnos a obtener estimaciones fiables del error de generalización del modelo, es decir, lo bien que se comporta el modelo en datos no vistos.

       El método holdout (método de retención)

     Es un enfoque clásico y popular para estimar el rendimiento de la generalización de los modelos de aprendizaje automático. Utilizando el método holdout (método de retención) dividimos nuestro conjunto de datos inicial en un conjunto de datos de entrenamiento y otro de prueba: el primero se utiliza para el entrenamiento del modelo y el segundo se utiliza para estimar su rendimiento. Sin embargo, en las aplicaciones típicas de aprendizaje automático, también nos interesa ajustar y comparar diferentes configuraciones de parámetros para mejorar aún más el rendimiento a la hora de realizar predicciones sobre datos no vistos. Este proceso se denomina selección de modelos, donde el término selección de modelos se refiere a un problema de clasificación dado para el que queremos seleccionar los valores óptimos de los parámetros de ajuste (también llamados hiperparámetros). Sin embargo, si reutilizamos el mismo conjunto de datos de prueba una y otra vez durante la selección del modelo, se convertirá en parte de nuestros datos de entrenamiento y, por tanto, será más probable que el modelo se ajuste en exceso. A pesar de este problema, mucha gente sigue utilizando el conjunto de pruebas para la selección del modelo, lo que no es una buena práctica de aprendizaje automático.
     Una forma mejor de utilizar el método holdout (método de retención) para la selección de modelos es separar los datos en tres partes: 
  •            Conjunto de entrenamiento 
  •            Conjunto de validación 
  •            Conjunto de prueba
      El conjunto de entrenamiento se utiliza para ajustar los diferentes modelos, y el rendimiento en el conjunto de validación se utiliza para la selección del modelo. La ventaja de contar con un conjunto de prueba que el modelo no ha visto antes durante los pasos de entrenamiento y selección del modelo es que podemos obtener una estimación menos sesgada de su capacidad de generalización a los nuevos datos. La siguiente figura ilustra el concepto de holdout cross-validation (validación cruzada de retención), en la que utilizamos un conjunto de validación para evaluar repetidamente el rendimiento del modelo tras el entrenamiento utilizando diferentes valores de los parámetros

Figura 6.1

   Desventaja: la estimación del rendimiento es sensible a la forma en que dividimos el conjunto de entrenamiento en subconjuntos de entrenamiento y validación; la estimación variará para diferentes muestras de los datos. En la siguiente sección, veremos una técnica más robusta para la estimación del rendimiento, la k-fold cross-validation (validación cruzada de k pliegues), en la que repetimos el método holdout (método de retención) k veces en k subconjuntos de los datos de entrenamiento.

       k-fold cross-validation (validación cruzada de k pliegues) 

     En la validación cruzada de k pliegues, dividimos aleatoriamente el conjunto de datos de entrenamiento en k pliegues sin reemplazo, donde se utilizan pliegues para el entrenamiento del modelo y un pliegue para las pruebas. Este procedimiento se repite k veces para obtener k modelos y estimaciones de rendimiento.

      A continuación, calculamos el rendimiento medio de los modelos basándonos en los diferentes pliegues independientes para obtener una estimación del rendimiento que sea menos sensible a la subdivisión de los datos de entrenamiento en comparación con el método holdout (método de retención). Normalmente, utilizamos la k-fold cross-validation (validación cruzada de k pliegues) para el ajuste del modelo, es decir, para encontrar los valores óptimos de los hiperparámetros que producen un rendimiento de generalización satisfactorio. Una vez que hayamos encontrado valores de hiperparámetros satisfactorios, podemos volver a entrenar el modelo en el conjunto de entrenamiento completo y obtener una estimación final del rendimiento utilizando el conjunto de pruebas independiente.

     Ventaja: cada punto de muestra formará parte de un conjunto de datos de entrenamiento y de prueba exactamente una vez, dado que la k-fold cross-validation (validación cruzada de k pliegues) es una técnica de remuestreo sin reemplazo,  lo que produce una estimación de la varianza del rendimiento del modelo más baja que el método holdout (método de retención). La siguiente figura resume el concepto de k-fold cross-validation (validación cruzada de k pliegues) con k =10 . El conjunto de datos de entrenamiento se divide en 10 pliegues, y durante las 10 iteraciones, se utilizan 9 pliegues para el entrenamiento, y 1 pliegue se utilizará como conjunto de prueba para la evaluación del modelo. Además, los rendimientos estimados  (por ejemplo, la precisión o el error de clasificación) de cada pliegue se utiliza para calcular el rendimiento medio estimado E del modelo:

Figura 6.2
       El valor estándar de k en la k-fold cross-validation (validación cruzada de k pliegues) es 10, que     suele ser una opción razonable para la mayoría de las aplicaciones. Sin embargo, si trabajamos con     conjuntos de entrenamiento relativamente pequeños o con grandes conjuntos de datos tendremos que tomar en cuenta lo siguiente: 
  •        Conjuntos de entrenamiento relativamente pequeños: en este caso puede ser útil aumentar el número de pliegues. Si aumentamos el valor de k, se utilizarán más datos de entrenamiento en cada iteración, lo que se traduce en un menor sesgo a la hora de estimar el rendimiento de la generalización promediando las estimaciones individuales del modelo. Sin embargo, los valores grandes de k también aumentarán el tiempo de ejecución del algoritmo de validación cruzada y producirán estimaciones con mayor varianza, ya que los pliegues de entrenamiento serán más similares entre sí.
  •       Grandes conjuntos de datos: en este caso podemos elegir un valor más pequeño para k, por ejemplo, k = 5 , y seguir obteniendo una estimación precisa del rendimiento medio del modelo, al tiempo que se reduce el coste computacional de reajustar y evaluar el modelo en los diferentes pliegues.

     Nota: Un caso especial de k-fold cross-validation (validación cruzada de k pliegues) es el método de leave-one-out (LOO) cross-validation. En LOO, establecemos el número de pliegues igual al número de muestras de entrenamiento (k = n), de modo que sólo se utiliza una muestra de entrenamiento para las pruebas durante cada iteración. Este es un método recomendado para trabajar con conjuntos de datos muy pequeños.

     Una ligera mejora sobre el enfoque de k-fold cross-validation (validación cruzada de k pliegues) estándar es la k-fold cross-validation (validación cruzada de k pliegues) estratificada.

      k-fold cross-validation (validación cruzada de k pliegues) estratificada.

    Es una versión mejorada de k-fold cross-validation (validación cruzada de k pliegues) estándar, ya que  puede producir mejores estimaciones de sesgo y varianza, especialmente en casos de proporciones de clase desiguales. En la validación cruzada estratificada, las proporciones de clase se conservan en cada pliegue para garantizar que cada pliegue es representativo de las proporciones de clase en el conjunto de datos de entrenamiento, lo que ilustraremos utilizando el iterador StratifiedKFold en scikit-learn:

>>> import numpy as np
>>> from sklearn.model_selection import StratifiedKFold
>>> kfold = StratifiedKFold(y=y_train,
...                         n_folds=10,
...                         random_state=1)
>>> scores = []
>>> for k, (train, test) in enumerate(kfold):
...    pipe_lr.fit(X_train[train], y_train[train])
...    score = pipe_lr.score(X_train[test], y_train[test])
...    scores.append(score)
...    print('Fold: %s, Class dist.: %s, Acc: %.3f' % (k+1, np.bincount(y_train[train]), score))
Fold: 1, Class dist.: [256 153], Acc: 0.891
Fold: 2, Class dist.: [256 153], Acc: 0.978
Fold: 3, Class dist.: [256 153], Acc: 0.978
Fold: 4, Class dist.: [256 153], Acc: 0.913
Fold: 5, Class dist.: [256 153], Acc: 0.935
Fold: 6, Class dist.: [257 153], Acc: 0.978
Fold: 7, Class dist.: [257 153], Acc: 0.933
Fold: 8, Class dist.: [257 153], Acc: 0.956
Fold: 9, Class dist.: [257 153], Acc: 0.978
Fold: 10, Class dist.: [257 153], Acc: 0.956 

Nota: cross_validation ya no es compatible. Usar solo sklearn.model_selection de ahora en adelante.
Por último, se calcula la desviación media y estándar de las puntuaciones del modelo:
>>> print('CV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
CV accuracy: 0.950 +/- 0.029
Aunque el ejemplo de código anterior fue útil para ilustrar cómo funciona la validación cruzada de k-pliegues, scikit-learn también implementa un puntaje de validación cruzada de k-pliegues, que nos permite evaluar nuestro modelo utilizando la validación cruzada de k-pliegues estratificada de manera más eficiente:
from sklearn.model_selection import cross_val_score
>>> scores = cross_val_score(estimator=pipe_lr,
...                          X=X_train,
...                          y=y_train,
...                          cv=10,
...                          n_jobs=-1)
>>> print('Puntuaciones de precisión (CV): %s' % scores)
Puntuaciones de precisión (CV): [0.91304348 0.97826087 0.97826087 0.91304348 0.93478261 0.97777778
 0.93333333 0.95555556 0.97777778 0.95555556]
Una característica extremadamente útil del enfoque cross_val_score es que podemos distribuir la evaluación de los diferentes pliegues entre múltiples CPUs de nuestra máquina. Si establecemos el parámetro n_jobs en 1, sólo se utilizará una CPU para evaluar los rendimientos. Sin embargo, estableciendo n_jobs=2 podríamos distribuir las 10 rondas de validación cruzada a dos CPUs (si están disponibles en nuestra máquina), y estableciendo n_jobs=-1, podemos utilizar todas las CPUs disponibles en nuestra máquina para hacer el cálculo en paralelo.

Bibliografía:

[1]    Raschka, S. (2015). Python Machine Learning. Pensilvania : Packt Publishing

Comentarios