Aplicación de métodos de envoltura en Python para la selección de características

En el artículo anterior, estudiamos cómo podemos usar métodos de filtro para la selección de características para algoritmos de aprendizaje automático. Los métodos de filtrado son útiles cuando desea...

Introducción

En el Artículo anterior, estudiamos cómo podemos usar métodos de filtro para la selección de características para algoritmos de aprendizaje automático. Los métodos de filtro son útiles cuando desea seleccionar un conjunto genérico de características para todos los modelos de aprendizaje automático.

Sin embargo, en algunos escenarios, es posible que desee utilizar un algoritmo de aprendizaje automático específico para entrenar su modelo. En tales casos, las funciones seleccionadas a través de métodos de filtro pueden no ser el conjunto de funciones más óptimo para ese algoritmo específico. Hay otra categoría de métodos de selección de características que seleccionan las características más óptimas para el algoritmo especificado. Dichos métodos se denominan métodos de envoltura.

Métodos de envoltorio para la selección de características

Los métodos de envoltura se basan en algoritmos de búsqueda codiciosos, ya que evalúan todas las combinaciones posibles de las funciones y seleccionan la combinación que produce el mejor resultado para un algoritmo de aprendizaje automático específico. Una desventaja de este enfoque es que probar todas las combinaciones posibles de las características puede ser computacionalmente muy costoso, particularmente si el conjunto de características es muy grande.

Como se dijo anteriormente, los métodos de envoltura pueden encontrar el mejor conjunto de funciones para un algoritmo específico; sin embargo, una desventaja es que este conjunto de funciones puede no ser óptimo para cualquier otro algoritmo de aprendizaje automático.

Los métodos de contenedor para la selección de funciones se pueden dividir en tres categorías: Selección de funciones paso adelante, Selección de funciones paso atrás y Selección exhaustiva de funciones. En este artículo, veremos cómo podemos implementar estos enfoques de selección de funciones en Python.

Selección de funciones paso adelante

En la primera fase de la selección de características paso a paso, se evalúa el rendimiento del clasificador con respecto a cada característica. La característica que funciona mejor se selecciona de todas las características.

En el segundo paso, la primera característica se prueba en combinación con todas las demás características. Se selecciona la combinación de dos características que producen el mejor rendimiento del algoritmo. El proceso continúa hasta que se selecciona el número especificado de características.

Implementemos la selección de características paso a paso en Python. Usaremos el conjunto de datos BNP Paribas Cardif Gestión de Siniestros para esta sección como lo hicimos en nuestro artículo anterior.

Para implementar la selección de funciones paso a paso, necesitamos convertir valores de funciones categóricos en valores de funciones numéricos. Sin embargo, en aras de la simplicidad, eliminaremos todas las columnas no categóricas de nuestros datos. También eliminaremos las columnas correlacionadas como hicimos en el artículo anterior para que tengamos un pequeño conjunto de funciones para procesar.

Preprocesamiento de datos {#preprocesamiento de datos}

El siguiente script importa el conjunto de datos y las bibliotecas requeridas, luego elimina las columnas no numéricas del conjunto de datos y luego divide el conjunto de datos en conjuntos de entrenamiento y prueba. Finalmente, se eliminan todas las columnas con una correlación superior a 0,8. Eche un vistazo a este artículo para obtener una explicación detallada de este script:

 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
32
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import VarianceThreshold

paribas_data = pd.read_csv(r"E:\Datasets\paribas_data.csv", nrows=20000)
paribas_data.shape

num_colums = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numerical_columns = list(paribas_data.select_dtypes(include=num_colums).columns)
paribas_data = paribas_data[numerical_columns]
paribas_data.shape

train_features, test_features, train_labels, test_labels = train_test_split(
    paribas_data.drop(labels=['target', 'ID'], axis=1),
    paribas_data['target'],
    test_size=0.2,
    random_state=41)

correlated_features = set()
correlation_matrix = paribas_data.corr()
for i in range(len(correlation_matrix .columns)):
    for j in range(i):
        if abs(correlation_matrix.iloc[i, j]) > 0.8:
            colname = correlation_matrix.columns[i]
            correlated_features.add(colname)


train_features.drop(labels=correlated_features, axis=1, inplace=True)
test_features.drop(labels=correlated_features, axis=1, inplace=True)

train_features.shape, test_features.shape
Implementación de la selección de funciones paso a paso en Python

Para seleccionar las funciones más óptimas, utilizaremos la función SequentialFeatureSelector de la biblioteca mlxtender. La biblioteca se puede descargar ejecutando el siguiente comando en el símbolo del sistema de anaconda:

1
conda install -c conda-forge mlxtend

Usaremos el Clasificador de bosque aleatorio para encontrar los parámetros más óptimos. El criterio de evaluación utilizado será República de China-AUC. El siguiente script selecciona las 15 características de nuestro conjunto de datos que ofrecen el mejor rendimiento para el clasificador de bosque aleatorio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score

from mlxtend.feature_selection import SequentialFeatureSelector

feature_selector = SequentialFeatureSelector(RandomForestClassifier(n_jobs=-1),
           k_features=15,
           forward=True,
           verbose=2,
           scoring='roc_auc',
           cv=4)

En el script anterior, pasamos RandomForestClassifier como el estimador a la función SequentialFeatureSelector. k_features especifica el número de características a seleccionar. Puede configurar cualquier número de características aquí. El parámetro ‘adelante’, si se establece en ‘Verdadero’, realiza una selección de funciones de paso adelante. El parámetro verbose se utiliza para registrar el progreso del selector de funciones, el parámetro scoring define los criterios de evaluación del rendimiento y, por último, cv se refiere a los pliegues de validación cruzada.

Creamos nuestro selector de funciones, ahora necesitamos llamar al método fit en nuestro selector de funciones y pasarle los conjuntos de entrenamiento y prueba como se muestra a continuación:

1
features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)

Dependiendo del hardware de su sistema, la secuencia de comandos anterior puede tardar algún tiempo en ejecutarse. Una vez que el script anterior termine de ejecutarse, puede ejecutar el siguiente script para ver las 15 funciones seleccionadas:

1
2
filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features

En la salida, debería ver las siguientes características:

1
2
3
Index(['v4', 'v10', 'v14', 'v15', 'v18', 'v20', 'v23', 'v34', 'v38', 'v42',
       'v50', 'v51', 'v69', 'v72', 'v129'],
      dtype='object')

Ahora, para ver el rendimiento de clasificación del algoritmo de bosque aleatorio utilizando estas 15 funciones, ejecute el siguiente script:

1
2
3
4
5
6
7
8
clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)

train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))

test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))

En el script anterior, entrenamos nuestro algoritmo de bosque aleatorio en las 15 funciones que seleccionamos mediante la selección de funciones paso adelante y luego evaluamos el rendimiento de nuestro algoritmo en los conjuntos de entrenamiento y prueba. En la salida, debería ver los siguientes resultados:

1
2
Accuracy on training set: 0.7072327148174093
Accuracy on test set: 0.7096973252804142

Puede ver que la precisión en los conjuntos de entrenamiento y prueba es bastante similar, lo que significa que nuestro modelo no se sobreajusta.

Paso atrás Selección de características

La selección de funciones hacia atrás, como sugiere el nombre, es exactamente lo contrario de la selección de funciones hacia adelante que estudiamos en la última sección. En el primer paso de la selección de funciones hacia atrás, se elimina una función del conjunto de funciones y se evalúa el rendimiento del clasificador.

Se conserva el conjunto de funciones que ofrece el mejor rendimiento. En el segundo paso, nuevamente se elimina una característica en forma rotativa y se evalúa el rendimiento de toda la combinación de características excepto las 2 características. Este proceso continúa hasta que el número especificado de entidades permanece en el conjunto de datos.

Retroceder en la selección de funciones en Python

En esta sección, implementaremos la selección de funciones de retroceso en BNP Paribas Cardif Gestión de Siniestros. El paso de preprocesamiento seguirá siendo el mismo que en la sección anterior. El único cambio será en el parámetro forward de la clase SequentiaFeatureSelector. En el caso de la selección de funciones de paso hacia atrás, estableceremos este parámetro en False. Ejecute el siguiente script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from mlxtend.feature_selection import SequentialFeatureSelector

feature_selector = SequentialFeatureSelector(RandomForestClassifier(n_jobs=-1),
           k_features=15,
           forward=False,
           verbose=2,
           scoring='roc_auc',
           cv=4)

features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)

Para ver la función seleccionada como resultado de la eliminación del paso hacia atrás, ejecute el siguiente script:

1
2
filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features

La salida se ve así:

1
2
3
Index(['v7', 'v8', 'v10', 'v17', 'v34', 'v38', 'v45', 'v50', 'v51', 'v61',
       'v94', 'v99', 'v119', 'v120', 'v129'],
      dtype='object')

Finalmente, evalúemos el rendimiento de nuestro clasificador de bosque aleatorio en las características seleccionadas como resultado de la selección de características paso a paso hacia atrás. Ejecute el siguiente script:

1
2
3
4
5
6
7
8
clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)

train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))

test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))

La salida se ve así:

1
2
Accuracy on training set: 0.7095207938140247
Accuracy on test set: 0.7114624676445211

Puede ver que el rendimiento logrado en el conjunto de entrenamiento es similar al logrado utilizando la selección de características de paso adelante. Sin embargo, en el conjunto de prueba, la selección de funciones hacia atrás funcionó un poco mejor.

Selección exhaustiva de funciones

En la selección exhaustiva de funciones, el rendimiento de un algoritmo de aprendizaje automático se evalúa frente a todas las combinaciones posibles de las funciones en el conjunto de datos. Se selecciona el subconjunto de funciones que ofrece el mejor rendimiento. El algoritmo de búsqueda exhaustiva es el algoritmo más codicioso de todos los métodos de envoltura, ya que prueba todas las combinaciones de características y selecciona la mejor.

Una desventaja de la selección exhaustiva de funciones es que puede ser más lenta en comparación con el método de avance y retroceso, ya que evalúa todas las combinaciones de funciones.

Selección exhaustiva de funciones en Python

En esta sección, implementaremos la selección de funciones de retroceso en BNP Paribas Cardif Gestión de Siniestros. El paso de preprocesamiento seguirá siendo similar al de la selección de funciones Paso adelante.

Para implementar una selección exhaustiva de funciones, utilizaremos la función ExhaustiveFeatureSelector de la biblioteca mlxtend.feature_selection. La clase tiene atributos min_features y max_features que se pueden usar para especificar el número mínimo y máximo de características en la combinación.

Ejecute el siguiente script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from mlxtend.feature_selection import ExhaustiveFeatureSelector
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score

feature_selector = ExhaustiveFeatureSelector(RandomForestClassifier(n_jobs=-1),
           min_features=2,
           max_features=4,
           scoring='roc_auc',
           print_progress=True,
           cv=2)

Creamos nuestro selector de funciones, ahora necesitamos llamar al método fit en nuestro selector de funciones y pasarle los conjuntos de entrenamiento y prueba como se muestra a continuación:

1
features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)

Tenga en cuenta que la secuencia de comandos anterior puede tardar bastante tiempo en ejecutarse. Para ver la función seleccionada como resultado de la eliminación del paso hacia atrás, ejecute el siguiente script:

1
2
filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features

Finalmente, para ver el rendimiento del clasificador de bosque aleatorio en las características seleccionadas como resultado de una selección exhaustiva de características. Ejecute el siguiente script:

1
2
3
4
5
6
7
8
clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)

train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))

test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))

Conclusión

Los métodos de envoltura son algunos de los algoritmos más importantes que se utilizan para la selección de funciones para un algoritmo de aprendizaje automático específico. En este artículo, estudiamos diferentes tipos de métodos de envoltura junto con su implementación práctica. Estudiamos paso adelante, paso atrás y métodos exhaustivos para la selección de características.

Como regla general, si el conjunto de datos es pequeño, el método de selección de características exhaustivo debe ser la opción; sin embargo, en el caso de conjuntos de datos grandes, se deben preferir los métodos de selección de características paso adelante o paso atrás.