Clasificación de conjunto/votación en Python con Scikit-Learn

Los modelos de clasificación de conjuntos pueden ser poderosas herramientas de aprendizaje automático capaces de lograr un rendimiento excelente y generalizar bien a conjuntos de datos nuevos e invisibles.

Introducción

Modelos de clasificación de conjuntos pueden ser poderosas herramientas de aprendizaje automático capaces de lograr un rendimiento excelente y generalizar bien a conjuntos de datos nuevos e invisibles.

El valor de un clasificador de conjunto es que, al unir las predicciones de múltiples clasificadores, puede corregir los errores cometidos por cualquier clasificador individual, lo que lleva a una mejor precisión general. Echemos un vistazo a los diferentes métodos de clasificación de conjuntos y veamos cómo se pueden implementar estos clasificadores en Scikit-Learn.

¿Qué son los modelos de conjunto en el aprendizaje automático? {#quésonlosmodelos de conjunto en el aprendizaje automático}

ensemble
[Crédito: pixabay]{.pequeño}

Los modelos de conjuntos son un método de aprendizaje de conjuntos que combina diferentes algoritmos. En este sentido, es un meta-algoritmo más que un algoritmo en sí mismo. Los métodos de aprendizaje por conjuntos son valiosos porque pueden mejorar el rendimiento de un modelo predictivo.

Los métodos de aprendizaje por conjuntos funcionan a partir de la idea de que vincular las predicciones de múltiples clasificadores conducirá a un mejor rendimiento al mejorar la precisión de la predicción o reducir aspectos como sesgo y varianza.

En general, un modelo de conjunto cae en una de dos categorías: enfoques secuenciales y enfoques paralelos.

Un modelo de conjunto secuencial opera teniendo los modelos/aprendices base generados en secuencia. Los métodos de conjunto secuencial se utilizan normalmente para intentar aumentar el rendimiento general, ya que el modelo de conjunto puede compensar las predicciones inexactas al volver a ponderar los ejemplos que anteriormente se clasificaron incorrectamente. Un ejemplo notable de esto es AdaBoost.

Un modelo paralelo es, como podrá adivinar, métodos que se basan en crear y capacitar a los alumnos base en paralelo. Los métodos paralelos tienen como objetivo reducir la tasa de error entrenando muchos modelos en paralelo y promediando los resultados juntos. Un ejemplo notable de método paralelo es el Clasificador de bosque aleatorio.

Otra forma de pensar sobre esto es una distinción entre estudiantes homogéneos y heterogéneos. Si bien la mayoría de los métodos de aprendizaje por conjuntos utilizan alumnos de base homogéneos (muchos del mismo tipo de alumnos), algunos métodos de conjuntos utilizan alumnos heterogéneos (diferentes algoritmos de aprendizaje unidos).

Recordar:

  • Los modelos secuenciales intentan aumentar el rendimiento al volver a ponderar los ejemplos, y los modelos se generan en secuencia.
  • Los modelos paralelos funcionan promediando los resultados después de entrenar muchos modelos al mismo tiempo.

Ahora cubriremos diferentes métodos de emplear estos modelos para resolver problemas de clasificación de aprendizaje automático.

Diferentes métodos de clasificación de conjuntos {#diferentes métodos de clasificación de conjuntos}

Embolsado

ensemble_bagging
[Crédito: Wikimedia Commons]{.pequeño}

Bagging, también conocido como agregación de arranque, es un método de clasificación que tiene como objetivo reducir la varianza de las estimaciones promediando varias estimaciones juntas. El embolsado crea subconjuntos del conjunto de datos principal en el que se capacita a los alumnos.

Para agregar las predicciones de los diferentes clasificadores, se usa un promedio para la regresión o un enfoque de votación para la clasificación (basado en la decisión de la mayoría).

Un ejemplo de un método de clasificación de embolsado es el Clasificador de bosques aleatorios. En el caso del clasificador de bosques aleatorios, todos los árboles individuales se entrenan en una muestra diferente del conjunto de datos.

El árbol también se entrena usando selecciones aleatorias de características. Cuando los resultados se promedian juntos, la varianza general disminuye y, como resultado, el modelo funciona mejor.

Impulso

Algoritmos de impulso son capaces de tomar modelos débiles y de bajo rendimiento y convertirlos en modelos sólidos. La idea detrás de los algoritmos de impulso es que usted asigna muchos modelos de aprendizaje débiles a los conjuntos de datos, y luego los pesos de los ejemplos mal clasificados se modifican durante las rondas de aprendizaje posteriores.

Las predicciones de los clasificadores se agregan y luego se hacen las predicciones finales a través de una suma ponderada (en el caso de regresiones), o un voto de mayoría ponderada (en el caso de clasificación).

AdaBoost es un ejemplo de un método de clasificador de impulso, al igual que Gradient Boosting, que se derivó del algoritmo mencionado anteriormente.

If you'd like to Lea más sobre el aumento de gradiente and the theory behind it, we've already covered that in a previous article.

Apilamiento

ensemble_stacking
[Crédito: Wikimedia Commons]{.small}

Algoritmos de apilamiento son un método de aprendizaje conjunto que combina la decisión de diferentes algoritmos de regresión o clasificación. Los modelos de componentes se entrenan en todo el conjunto de datos de entrenamiento. Después de entrenar estos modelos de componentes, se ensambla un metamodelo a partir de los diferentes modelos y luego se entrena con los resultados de los modelos de componentes. Este enfoque generalmente crea un conjunto heterogéneo porque los modelos de componentes suelen ser algoritmos diferentes.

Implementaciones de ejemplo {#implementaciones de ejemplo}

Ahora que hemos explorado diferentes métodos que podemos usar para crear modelos de conjunto, echemos un vistazo a cómo podríamos implementar un clasificador usando los diferentes métodos.

Sin embargo, antes de que podamos echar un vistazo a las diferentes formas de implementar clasificadores de conjunto, debemos seleccionar un conjunto de datos para usar y realizar un preprocesamiento del conjunto de datos.

Usaremos el conjunto de datos Titanic, que puede ser descargado aquí. Hagamos un preprocesamiento de los datos para deshacernos de los valores faltantes y escalar los datos a un rango uniforme. Luego podemos comenzar a configurar los clasificadores de conjunto.

Preprocesamiento de datos {#preprocesamiento de datos}

Para empezar, comenzaremos importando todas las funciones que necesitamos de sus respectivas bibliotecas. Usaremos pandas y entumecido para cargar y transformar los datos, así como LabelEncoder y Herramientas StandardScaler.

También necesitaremos las métricas de aprendizaje automático y la función train_test_split. Finalmente, necesitaremos los clasificadores que queremos usar:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pandas as pd
import numpy as np
import warnings

from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.metrics import accuracy_score, f1_score, log_loss
from sklearn.model_selection import train_test_split, KFold, cross_val_score

from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import AdaBoostClassifier, RandomForestClassifier, ExtraTreesClassifier

Comenzaremos cargando los datos de entrenamiento y prueba y luego creando una función para verificar la presencia de valores nulos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
training_data = pd.read_csv("train.csv")
testing_data = pd.read_csv("test.csv")

def get_nulls(training, testing):
    print("Training Data:")
    print(pd.isnull(training).sum())
    print("Testing Data:")
    print(pd.isnull(testing).sum())

get_nulls(training_data, testing_data)

Da la casualidad de que faltan muchos valores en las categorías “Edad” y “Cabina”.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Training Data:
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64
Testing Data:
PassengerId      0
Pclass           0
Name             0
Sex              0
Age             86
SibSp            0
Parch            0
Ticket           0
Fare             1
Cabin          327
Embarked         0
dtype: int64

Vamos a comenzar eliminando algunas de las columnas que probablemente serán inútiles: la columna “Cabina” y la columna “Boleto”. La columna “Cabina” tiene demasiados valores faltantes y la columna “Boleto” simplemente se compone de demasiadas categorías para ser útil.

Después de eso, necesitaremos imputar algunos valores faltantes. Cuando lo hacemos, debemos tener en cuenta cómo el conjunto de datos está ligeramente sesgado a la derecha (las edades jóvenes son ligeramente más prominentes que las edades mayores). Usaremos los valores medianos cuando imputemos los datos porque, debido a los grandes valores atípicos, tomar los valores promedio nos daría valores imputados que están lejos del centro del conjunto de datos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Drop the cabin column, as there are too many missing values
# Drop the ticket numbers too, as there are too many categories
# Drop names as they won't really help predict survivors

training_data.drop(labels=['Cabin', 'Ticket', 'Name'], axis=1, inplace=True)
testing_data.drop(labels=['Cabin', 'Ticket', 'Name'], axis=1, inplace=True)

# Taking the mean/average value would be impacted by the skew
# so we should use the median value to impute missing values

training_data["Age"].fillna(training_data["Age"].median(), inplace=True)
testing_data["Age"].fillna(testing_data["Age"].median(), inplace=True)
training_data["Embarked"].fillna("S", inplace=True)
testing_data["Fare"].fillna(testing_data["Fare"].median(), inplace=True)

get_nulls(training_data, testing_data)

Ahora podemos ver que no faltan más valores:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Training Data:
PassengerId    0
Survived       0
Pclass         0
Name           0
Sex            0
Age            0
SibSp          0
Parch          0
Fare           0
Embarked       0
dtype: int64
Testing Data:
PassengerId    0
Pclass         0
Name           0
Sex            0
Age            0
SibSp          0
Parch          0
Fare           0
Embarked       0
dtype: int64

Ahora vamos a necesitar codificar los datos no numéricos. Configuremos un LabelEncoder y colóquelo en la característica Sex y luego transforme los datos con el codificador. Luego reemplazaremos los valores en la función Sexo con aquellos que han sido codificados y luego haremos lo mismo para la función Embarcado.

Finalmente, vamos a escalar los datos usando el StandardScaler, para que no haya grandes fluctuaciones en los valores.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
encoder_1 = LabelEncoder()
# Fit the encoder on the data
encoder_1.fit(training_data["Sex"])

# Transform and replace training data
training_sex_encoded = encoder_1.transform(training_data["Sex"])
training_data["Sex"] = training_sex_encoded
test_sex_encoded = encoder_1.transform(testing_data["Sex"])
testing_data["Sex"] = test_sex_encoded

encoder_2 = LabelEncoder()
encoder_2.fit(training_data["Embarked"])

training_embarked_encoded = encoder_2.transform(training_data["Embarked"])
training_data["Embarked"] = training_embarked_encoded
testing_embarked_encoded = encoder_2.transform(testing_data["Embarked"])
testing_data["Embarked"] = testing_embarked_encoded

# Any value we want to reshape needs be turned into array first
ages_train = np.array(training_data["Age"]).reshape(-1, 1)
fares_train = np.array(training_data["Fare"]).reshape(-1, 1)
ages_test = np.array(testing_data["Age"]).reshape(-1, 1)
fares_test = np.array(testing_data["Fare"]).reshape(-1, 1)

# Scaler takes arrays
scaler = StandardScaler()

training_data["Age"] = scaler.fit_transform(ages_train)
training_data["Fare"] = scaler.fit_transform(fares_train)
testing_data["Age"] = scaler.fit_transform(ages_test)
testing_data["Fare"] = scaler.fit_transform(fares_test)

Ahora que nuestros datos han sido preprocesados, podemos seleccionar nuestras características y etiquetas y luego usar la función train_test_split para dividir todos nuestros datos de entrenamiento en conjuntos de entrenamiento y prueba:

1
2
3
4
5
6
7
8
9
# Now to select our training/testing data
X_features = training_data.drop(labels=['PassengerId', 'Survived'], axis=1)
y_labels = training_data['Survived']

print(X_features.head(5))

# Make the train/test data from validation

X_train, X_val, y_train, y_val = train_test_split(X_features, y_labels, test_size=0.1, random_state=27)

Ahora estamos listos para comenzar a implementar métodos de clasificación de conjuntos.

Enfoque de promedio simple

Antes de entrar en los tres grandes métodos de conjunto que cubrimos anteriormente, cubramos un método muy rápido y fácil de usar un enfoque de conjunto: [promedio de predicciones] (https://www.analyticsvidhya.com/blog/2018/ 06/guía-completa-para-modelos-de-conjuntos/). Simplemente sumamos los diferentes valores pronosticados de nuestros clasificadores elegidos y luego los dividimos por el número total de clasificadores, usando la división mínima para obtener un valor total.

En este caso de prueba, utilizaremos la regresión logística, un [Clasificador de árboles de decisión](/árboles de decisión-en-python-con-scikit-learn/) y el [Clasificador de vectores de soporte] (/implementing-swim- and-kernel-swim-with-pythons-scikit-learn/). Ajustamos los clasificadores a los datos y luego guardamos las predicciones como variables. Luego simplemente sumamos las predicciones y dividimos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
LogReg_clf = LogisticRegression()
DTree_clf = DecisionTreeClassifier()
SVC_clf = SVC()

LogReg_clf.fit(X_train, y_train)
DTree_clf.fit(X_train, y_train)
SVC_clf.fit(X_train, y_train)

LogReg_pred = LogReg_clf.predict(X_val)
DTree_pred = DTree_clf.predict(X_val)
SVC_pred = SVC_clf.predict(X_val)

averaged_preds = (LogReg_pred + DTree_pred + SVC_pred)//3
acc = accuracy_score(y_val, averaged_preds)
print(acc)

Aquí está la precisión que obtuvimos de este método:

1
0.8444444444444444

Votación\Ejemplo de clasificación de apilamiento

Cuando se trata de crear un clasificador de apilamiento/votación, Scikit-Learn nos brinda algunas funciones útiles que podemos usar para lograrlo.

El Clasificador de votaciones toma una lista de diferentes estimadores como argumentos y un método de votación. El método de votación “dura” utiliza las etiquetas pronosticadas y un sistema de reglas de mayoría, mientras que el método de votación “suave” predice una etiqueta basada en el argmax/valor predicho más grande de la suma de las probabilidades predichas.

Después de proporcionar los clasificadores deseados, debemos ajustar el objeto clasificador de conjunto resultante. Luego podemos obtener predicciones y usar métricas de precisión:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
voting_clf = VotingClassifier(estimators=[('SVC', SVC_clf), ('DTree', DTree_clf), ('LogReg', LogReg_clf)], voting='hard')
voting_clf.fit(X_train, y_train)
preds = voting_clf.predict(X_val)
acc = accuracy_score(y_val, preds)
l_loss = log_loss(y_val, preds)
f1 = f1_score(y_val, preds)

print("Accuracy is: " + str(acc))
print("Log Loss is: " + str(l_loss))
print("F1 Score is: " + str(f1))

Esto es lo que dicen las métricas sobre el rendimiento de VotingClassifier:

1
2
3
Accuracy is: 0.8888888888888888
Log Loss is: 3.8376684749044165
F1 Score is: 0.8484848484848486

Ejemplo de clasificación de embolsado

Así es como podemos implementar la clasificación de embolsado con Scikit-Learn. El Clasificador de embolsado de Sklearn’s toma un modelo de clasificación elegido, así como la cantidad de estimadores que desea para usar: puede usar un modelo como Regresión logística o Árboles de decisión.

Sklearn también proporciona acceso a RandomForestClassifier y ExtraTreesClassifier, que son modificaciones de la clasificación del árbol de decisión. Estos clasificadores también se pueden usar junto con la herramienta de validación cruzada K-folds.

Compararemos varios enfoques de clasificación de embolsado diferentes aquí, imprimiendo los resultados medios de la puntuación de validación cruzada de K-fold:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
logreg_bagging_model = BaggingClassifier(base_estimator=LogReg_clf, n_estimators=50, random_state=12)
dtree_bagging_model = BaggingClassifier(base_estimator=DTree_clf, n_estimators=50, random_state=12)
random_forest = RandomForestClassifier(n_estimators=100, random_state=12)
extra_trees = ExtraTreesClassifier(n_estimators=100, random_state=12)

def bagging_ensemble(model):
    k_folds = KFold(n_splits=20, random_state=12)
    results = cross_val_score(model, X_train, y_train, cv=k_folds)
    print(results.mean())

bagging_ensemble(logreg_bagging_model)
bagging_ensemble(dtree_bagging_model)
bagging_ensemble(random_forest)
bagging_ensemble(extra_trees)

Aquí están los resultados que obtuvimos de los clasificadores:

1
2
3
4
0.7865853658536585
0.8102439024390244
0.8002439024390245
0.7902439024390244

Ejemplo de clasificación de impulso

Finalmente, veremos cómo usar un método de clasificación de impulso. Como se mencionó, hay un artículo separado sobre el tema de Gradient Boosting que puede leer aquí.

Scikit-Learn tiene incorporado un Clasificador AdaBoost, que toma un número determinado de estimadores como primer argumento . Podemos intentar usar un bucle for para ver cómo cambia el rendimiento de la clasificación en diferentes valores, y también podemos combinarlo con la herramienta de validación cruzada K-Folds:

1
2
3
4
5
6
7
8
9
k_folds = KFold(n_splits=20, random_state=12)

num_estimators = [20, 40, 60, 80, 100]

for i in num_estimators:
    ada_boost = AdaBoostClassifier(n_estimators=i, random_state=12)
    results = cross_val_score(ada_boost, X_train, y_train, cv=k_folds)
    print("Results for {} estimators:".format(i))
    print(results.mean())

Aquí están los resultados que obtuvimos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Results for 20 estimators:
0.8015243902439024
Results for 40 estimators:
0.8052743902439025
Results for 60 estimators:
0.8053048780487805
Results for 80 estimators:
0.8040243902439024
Results for 100 estimators:
0.8027743902439024

Yendo más lejos: proyecto de extremo a extremo portátil

¿Tu naturaleza inquisitiva te hace querer ir más allá? Recomendamos consultar nuestro Proyecto guiado: ["Predicción práctica del precio de la vivienda: aprendizaje automático en Python"](https://wikihtp.com/courses/hands-on-house- precio-predicción-aprendizaje-máquina-en-python/#cta){target="_blank"}.

[](https://wikihtp.com/ cursos/predicción-de-precio-de-la-casa-práctica-aprendizaje-de-máquina-en-python/#cta)

En este proyecto guiado, aprenderá a crear potentes modelos tradicionales de aprendizaje automático, así como modelos de aprendizaje profundo, utilizar Ensemble Learning y capacitar a los meta-aprendices para predecir los precios de la vivienda a partir de una bolsa de modelos Scikit-Learn y Keras.

Con Keras, la API de aprendizaje profundo creada sobre Tensorflow, experimentaremos con arquitecturas, crearemos un conjunto de modelos apilados y entrenaremos una red neuronal meta-aprendizaje (modelo de nivel 1) para averiguar el precio de un casa.

El aprendizaje profundo es sorprendente, pero antes de recurrir a él, se recomienda intentar resolver el problema con técnicas más simples, como los algoritmos de aprendizaje superficial. Nuestro rendimiento de referencia se basará en un algoritmo de Regresión de bosque aleatorio. Además, exploraremos la creación de conjuntos de modelos a través de Scikit-Learn a través de técnicas como embalaje y votación.

Este es un proyecto integral y, como todos los proyectos de aprendizaje automático, comenzaremos con Análisis exploratorio de datos, seguido de Preprocesamiento de datos y, finalmente, Creación de modelos de aprendizaje superficial y Profundo para ajustarse a los datos que hemos explorado y limpiado previamente.

Resumiendo

Hemos cubierto las ideas detrás de tres técnicas diferentes de clasificación de conjuntos: votación\apilado, embolsado y potenciado.

Scikit-Learn le permite crear fácilmente instancias de los diferentes clasificadores de conjuntos. Estos objetos de conjunto se pueden combinar con otras herramientas de Scikit-Learn como la validación cruzada de K-Folds.