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

C

Introducción

Modelos de clasificación de conjuntos pueden ser potentes herramientas de Machine Learning 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 conduce a una mejor precisión en 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 conjuntos en el Machine Learning?

 

Crédito: Pixabay

Los modelos de conjunto son un método de aprendizaje de conjunto 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 se basan en la idea de que unir las predicciones de múltiples clasificadores conducirá a un mejor rendimiento ya sea mejorando la precisión de la predicción o reduciendo aspectos como el sesgo y la varianza.

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

Un modelo de conjunto secuencial opera haciendo que los modelos / aprendices base se generen 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 volviendo a ponderar los ejemplos que anteriormente se clasificaron erróneamente. Un ejemplo notable de esto es AdaBoost.

Un modelo paralelo es, como puede 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 un método paralelo es el clasificador de bosque aleatorio.

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

Recordar:

  • Los modelos secuenciales intentan aumentar el rendimiento volviendo a ponderar los ejemplos y los modelos se generan en secuencia.
  • Los modelos paralelos funcionan promediando los resultados juntos 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 Machine Learning.

Diferentes métodos de clasificación de conjuntos

Harpillera

 

Crédito: Wikimedia Commons

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

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

Un ejemplo de método de clasificación de ensacado 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 mediante selecciones aleatorias de características. Cuando los resultados se promedian juntos, la varianza general disminuye y el modelo funciona mejor como resultado.

Impulsar

Impulsar algoritmos 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 se asignan muchos modelos de aprendizaje débiles a los conjuntos de datos, y luego se ajustan las ponderaciones de los ejemplos mal clasificados durante las rondas posteriores de aprendizaje.

Las predicciones de los clasificadores se agregan y luego las predicciones finales se realizan mediante una suma ponderada (en el caso de regresiones), o un voto mayoritario ponderado (en el caso de clasificación).

AdaBoost es un ejemplo de un método de clasificador de refuerzo, como lo es Gradient Boosting, que se derivó del algoritmo mencionado anteriormente.

Si desea leer más sobre Gradient Boosting y la teoría detrás de él, ya lo hemos cubierto en un artículo anterior.

Apilado

 

Crédito: Wikimedia Commons

Algoritmos de apilamiento son un método de aprendizaje por conjuntos 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 en 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

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 conjuntos, debemos seleccionar un conjunto de datos para usar y hacer 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 perdidos y escalar los datos a un rango uniforme. Luego podemos empezar a configurar los clasificadores de conjuntos.

Preprocesamiento de datos

Para empezar, comenzaremos importando todas las funciones que necesitamos de sus respectivas bibliotecas. Estaremos usando Pandas y Numpy para cargar y transformar los datos, así como la LabelEncoder y StandardScaler herramientas.

También necesitaremos las métricas de Machine Learning y train_test_split función. Finalmente, necesitaremos los clasificadores que queremos usar:

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 crearemos una función para verificar la presencia de valores nulos:

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 hay muchos valores perdidos en el Age y Cabin categorías.

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

Comenzaremos eliminando algunas de las columnas que probablemente serán inútiles: el Cabin columna y el Ticket columna. los Cabin columna tiene demasiados valores perdidos y el Ticket La columna simplemente se compone de demasiadas categorías para ser útil.

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

# 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 hay más valores perdidos:

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. Vamos a configurar un LabelEncoder y colocarlo en el Sex característica y luego transformar los datos con el codificador. Luego reemplazaremos los valores en el Sex función con los que se han codificado y luego hacer lo mismo para el Embarked característica.

Finalmente, escalemos los datos usando el StandardScaler, por lo que no hay grandes fluctuaciones en los valores.

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 el train_test_split función para dividir todos nuestros datos de entrenamiento en conjuntos de entrenamiento y prueba:

# 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 por conjuntos.

Enfoque de promediado 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: promediar predicciones. Simplemente sumamos los diferentes valores predichos de nuestros clasificadores elegidos juntos y luego dividimos por el número total de clasificadores, usando la división de piso para obtener un valor total.

En este caso de prueba, usaremos regresión logística, un clasificador de árbol de decisión y el clasificador de vectores de soporte. Ajustamos los clasificadores a los datos y luego guardamos las predicciones como variables. Luego, simplemente sumamos las predicciones y dividimos:

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 con este método:

0.8444444444444444

Ejemplo de clasificación de votación / apilamiento

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

los VotingClassifier toma una lista de diferentes estimadores como argumentos y un método de votación. los hard El método de votación utiliza las etiquetas previstas y un sistema de reglas de mayoría, mientras que soft El método de votación predice una etiqueta basada en argmax / mayor valor predicho de la suma de las probabilidades predichas.

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

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 la VotingClassifierrendimiento de:

Accuracy is: 0.8888888888888888
Log Loss is: 3.8376684749044165
F1 Score is: 0.8484848484848486

Ejemplo de clasificación de ensacado

A continuación, se explica cómo podemos implementar la clasificación de ensacado con Scikit-Learn. Sklearn’s Clasificador de ensacado toma en un modelo de clasificación elegido, así como el número de estimadores que desea usar; puede usar un modelo como Regresión logística o Árboles de decisión.

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

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

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)

Estos son los resultados que obtuvimos de los clasificadores:

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 una función Clasificador AdaBoost, que toma un número dado 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 de K-Folds:

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())

Estos son los resultados que obtuvimos:

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

Resumiendo

Hemos cubierto las ideas detrás de tres técnicas diferentes de clasificación de conjuntos: votación apilamiento, ensacado y refuerzo.

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.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad