DEV Community

loading...
Cover image for Guia rápida sobre Ensemble Learning

Guia rápida sobre Ensemble Learning

Leandro Ruiz
Soy un cientifico de datos argentino. I'm a data scientist from Argentina.
・6 min read

En muchas ocasiones, los cientificos de datos nos enfrentamos a la decisión sobre qué modelo usar para una determinada tarea de regresión o clasificación. Pero ante este dilema hay una respuesta sencilla que puede encajar muy bien en la mayoría de los proyectos.

Esta respuesta es nada mas ni nada menos que el Ensemble Learning (o aprendizaje en conjunto en su traducción al español).

Introducción a Ensemble Learning

En el campo del aprendizaje automático, si agrupamos las predicciones de un conjunto de algoritmos (tanto para clasificación como para regresión) vamos a obtener mejores resultados que con el mejor predictor individual.

Por ejemplo:

Entrenamos un grupo de Decision Trees, cada uno con un sub-grupo diferente de datos de entrenamiento. Luego, para realizar predicciones lo que hacemos es obtener los resultados de cada arbol y predecir la clase que obtiene mas votos (en caso de regresión, es el promedio de todas las predicciones).

Decision Trees


Veamos un ejemplo rapido para ver como funciona este metodo usando Scikit-Learn:

from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import VotingClassifier
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split

log_clf = LogisticRegression()
rnd_clf = RandomForestClassifier()
svm_clf = SVC()

voting_clf = VotingClassifier(
    estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
    voting='hard')

X, y = make_moons(n_samples=1000, noise=0.3, random_state=42)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.35, random_state=42)

from sklearn.metrics import accuracy_score

for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
  clf.fit(X_train, y_train)
  y_pred = clf.predict(X_test)
  print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
Enter fullscreen mode Exit fullscreen mode
LogisticRegression 0.8514285714285714
RandomForestClassifier 0.9142857142857143
SVC 0.9028571428571428
VotingClassifier 0.9057142857142857
Enter fullscreen mode Exit fullscreen mode

Lo primero que hacemos es definir los modelos que vamos a agrupar para crear nuestro algoritmo. En este caso, vamos a usar RandomForestClassifier, LogisticRegression y SVC (Support Vector Classifier). Luego, agrupamos los tres modelos usando el metodo VotingClassifier y lo entrenamos.

El Ensemble Learning funciona mejor si los algoritmos a agrupar son los mas independientes posibles unos de otros. De esta manera, van a realizar distintos tipos de errores, mejorando la precisión del conjunto.


Diferencias entre hard y soft voting.

Si todos los clasificadores son capaces de estimar las probabilidades de cada clase (es decir, tienen disponible el metodo predict_proba()), entonces podemos configurar nuestro algoritmo grupal para que prediga la clase con la mayor probabilidad por clase, promediando los resultados dados por cada algoritmo. Esta tecnica es conocida como soft voting. En algunas ocasiones es capaz de obtener mejores resultados que el hard voting porque le da mayor peso a los votos mas probables de ser correctos. Lo unico que hay que hacer es reemplazar voting="hard" por voting="soft" y asegurarnos que todos los clasificadores estiman las probabilidades por clase. De manera predeterminada SVC no tiene esta opcion activada, por lo que debes configurar el hiper-parámetro probability como True (lo que hará que SVC use cross-validation para estimar las probabilidades de cada clase, volviendo mas lento el entrenamiento, y añadiendo el metodo predict_proba()).

Veamos como queda nuestro modelo en conjunto luego de estas modificaciones:

log_clf = LogisticRegression()
rnd_clf = RandomForestClassifier()
svm_clf = SVC(probability=True)

voting_clf = VotingClassifier(
    estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
    voting='soft')

for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
  clf.fit(X_train, y_train)
  y_pred = clf.predict(X_test)
  print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
Enter fullscreen mode Exit fullscreen mode
LogisticRegression 0.8514285714285714
RandomForestClassifier 0.92
SVC 0.9028571428571428
VotingClassifier 0.9142857142857143
Enter fullscreen mode Exit fullscreen mode

Como podemos ver, nuestro modelo obtuvo unos resultados ligeramente mejores con soft voting.


Bagging y Pasting

Como ya vimos, una manera de tener un diverso grupo de clasificadores es usar diferentes algoritmos en la etapa de entrenamiento. Pero otra forma de obtener esto es usando un solo algoritmo durante todo el proceso pero entrenarlos con distintas porciones del set de datos de entrenamiento. Cuando el muestreo de datos se realiza con reemplazamientos, este metodo se llama bagging (abreviatura de bootstrap aggregating). Y cuando el muestreo es sin reemplazamiento, es llamado pasting.

En otras palabras, tanto el bagging como el pasting permiten muestrear instancias de entrenamiento varias veces en varios predictores, pero solo el bagging permite muestrear instancias de entrenamiento varias veces para el mismo predictor.


GitHub Button

Link a GitHub


Una vez que todos los predictores son entrenados, el conjunto puede realizar una predicción para una nueva instancia agregando las predicciones de todos los predictores. La función de agregación es normalmente el modo estadístico (es decir, la predicción más frecuente, como un clasificador hard voting) para clasificación, o el promedio para regresión. Cada predictor individual tiene un sesgo mayor que si hubiera sido entrenado con el set de datos original, pero la agregación reduce el sesgo y la varianza. Generalmente, el resultado final es que el conjunto tiene un sesgo similar pero una varianza menor que un solo predictor entrenado con el set original.


Bagging y Pasting en Scikit-Learn

Se puede usar BaggingClassifier para tareas de clasificación, y BaggingRegressor para regresión.

Algunos parámetros para bagging son:

  • n_estimators: número de predictores en el conjunto.
  • max_samples: número de muestras del set de entrenamiento para entrenar cada predictor.
  • bootstrap: True para usar bagging, False para usar pasting.
  • n_jobs: número de núcleos del CPU para usar en el entrenamiento (-1 usa todos los núcleos disponibles).

Acá tenemos un ejemplo de bagging:

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier

bag_clf = BaggingClassifier(
    DecisionTreeClassifier(), n_estimators=1000,
    max_samples=200, bootstrap=True, n_jobs=-1, random_state=0)
bag_clf.fit(X_train, y_train)
y_pred = bag_clf.predict(X_test)

print(accuracy_score(y_test, y_pred))
Enter fullscreen mode Exit fullscreen mode
0.9057142857142857
Enter fullscreen mode Exit fullscreen mode

Y por acá un ejemplo de pasting:

pas_clf = BaggingClassifier(
    DecisionTreeClassifier(), n_estimators=1000,
    max_samples=200, bootstrap=False, n_jobs=-1, random_state=0)
pas_clf.fit(X_train, y_train)
y_pred = pas_clf.predict(X_test)

print(accuracy_score(y_test, y_pred))
Enter fullscreen mode Exit fullscreen mode
0.9085714285714286
Enter fullscreen mode Exit fullscreen mode

Y por el simple hecho de comparar, veamos como resulta un solo Decision Tree haciendo todo el trabajo:

tree = DecisionTreeClassifier()
tree.fit(X_train, y_train)
y_pred = tree.predict(X_test)
print(accuracy_score(y_test, y_pred))
Enter fullscreen mode Exit fullscreen mode
0.8714285714285714
Enter fullscreen mode Exit fullscreen mode

Tal como se esperaba, tenemos mejores resultados usando 1000 arboles en lugar de 1.

Conclusión

Espero que este articulo les haya ayudado tanto como me ayudó a mi mientras lo confeccionaba. Muchas gracias por llegar hasta aquí y ¡hasta la proxima!

Fin


¡Sorpresa para quienes llegaron al final!


Evaluación Out-of-Bag

Cuando usamos bagging, algunas instancias pueden ser seleccionadas varias veces para cualquier predictor, mientras que otros pueden no ser seleccionados en absoluto. Predeterminadamente, BaggingClassifier selecciona m instancias de entrenamiento con reemplazamiento (bootstrap=True), donde m es el tamaño del set de entrenamiento. Esto significa que en promedio solo el 63 % de las instancias de entrenamiento son seleccionadas para cada predictor. El 37 % restante (que no son las mismas para todos los predictores) de las instancias que no son muestreadas son llamadas instancias out-of-bag (oob).

Ya que un predictor nunca ve las instancias oob durante el entrenamiento, pueden ser utilizadas para evaluar sin la necesidad de un set de validación. Puedes evaluar al conjunto en si al promediar las evaluaciones oob para cada predictor.

En Scikit-Learn, puedes configurar oob_score=True cuando estas creando un BaggingClassifier para pedir una evaluación oob luego del entrenamiento. El resultado de la evaluación esta disponible a través de la variable oob_score:

bag_clf = BaggingClassifier(
    DecisionTreeClassifier(), n_estimators=500,
    bootstrap=True, n_jobs=-1, oob_score=True)

bag_clf.fit(X_train, y_train)
bag_clf.oob_score_
Enter fullscreen mode Exit fullscreen mode
0.9061538461538462
Enter fullscreen mode Exit fullscreen mode

De acuerdo a esta evaluación oob, este BaggingClassifier es capaz de alcanzar un 90.6 % de precisión en el test set. Vamos a verificarlo:

y_pred = bag_clf.predict(X_test)
accuracy_score(y_test, y_pred)
Enter fullscreen mode Exit fullscreen mode
0.9142857142857143
Enter fullscreen mode Exit fullscreen mode

¡Obtuvimos un 91.4 % de precision en el set de prueba! Bastante acertado.

Incluso tambien tenemos disponible la función de decisión oob:

bag_clf.oob_decision_function_
Enter fullscreen mode Exit fullscreen mode
array([[0.        , 1.        ],
       [0.97206704, 0.02793296],
       [1.        , 0.        ],
       ...,
       [0.99408284, 0.00591716],
       [0.88333333, 0.11666667],
       [0.        , 1.        ]])
Enter fullscreen mode Exit fullscreen mode

Ahora sí es el final, muchas gracias por leerme. ¡Hasta luego!

Discussion (0)