En el aprendizaje automático, la selección de características importantes en los datos es una parte importante del ciclo completo.
El entrenamiento del modelo con características irrelevantes puede afectar el rendimiento del modelo. Para evitarlo, se utilizan métodos de reducción de la dimensionalidad.
Existen varios tipos:
Dos categorías:
Vamos a ver ejemplos de algunos métodos de filtro univariante y multivariante.
Para este ejemplo, utilizaremos un conjunto de datos de satisfacción de clientes del Santander.
Primero importamos las bibliotecas necesarias y cargamos los datos (cargamos sólo los primeros 40.000 datos):
import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.feature_selection import VarianceThreshold # Configuración warnings # ============================================================================== import warnings warnings.filterwarnings('ignore')
datos = pd.read_csv("santander.csv", nrows=40000) datos.shape
(40000, 371)
Como vemos, el dataset contiene 40.000 datos con 371 variables (370 características y nuestra variable objetivo, que, en este caso, es la columna TARGET).
Antes de nada, es importante separar siempre los datos en entrenamiento y test para evitar el sobreajuste.
X = datos.drop(columns = 'TARGET', axis = 1) y = datos['TARGET']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.7)
Para saber las características constantes (varianza 0), vamos a usar la función VarianceThreshold de la librería sklearn. Esta función, selecciona las características eliminando las que tienen una varianza por debajo de un umbral (en este caso, 0). Primero tenemos que crear el filtro, y después aplicarlo a nuestros datos de entrenamiento.
constant_filter = VarianceThreshold(threshold=0) constant_filter.fit(X_train)
Para obtener todas las características que no son constantes, podemos usar la función get_support() del filtro que creamos.
len(X_train.columns[constant_filter.get_support()])
301
Como vemos, hay 301 características no constantes, con lo que tenemos 69 que sí lo son. Finalmente, para eliminar características constantes de los conjuntos de entrenamiento y prueba, podemos usar el método transform() del filtro.
X_train = constant_filter.transform(X_train) X_test = constant_filter.transform(X_test) X_train.shape, X_test.shape
((28000, 301), (12000, 301))
Si quisiéramos eliminar las características cuasi constantes, podemos variar el umbral del filtro:
constant_filter = VarianceThreshold(threshold=0.1) constant_filter.fit(X_train)
len(X_train.columns[constant_filter.get_support()])
204
X_train = constant_filter.transform(X_train) X_test = constant_filter.transform(X_test) X_train.shape, X_test.shape
((28000, 204), (12000, 204))
Vamos a ver un ejemplo de método de filtro multivariante, eliminando características que están altamente correlacionadas entre sí.
En este caso, vamos a utilizar el dataset wine de la librería sklearn. Importamos las librerías, cargamos los datos y separamos test y entrenamiento.
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split # Configuración warnings # ============================================================================== import warnings warnings.filterwarnings('ignore')
data = load_wine() df = pd.DataFrame(data = data.data, columns = data.feature_names) df['class'] = data.target df.shape
(178, 14)
Nuestro conjunto de datos tiene 178 registros con 13 características (más nuestra variable objetivo, que es class).
X = df.drop(columns = 'class', axis = 1) y = df['class']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.7)
Primero, sacamos la matriz de correlación de las características con el método corr() y mostramos el gráfico con un mapa de colores.
figure = plt.figure(figsize = (15, 10)) axes = figure.add_subplot() corr_features = X_train.corr() _ = sns.heatmap(corr_features, annot=True, cmap=plt.cm.coolwarm, axes = axes)
Lo siguiente será sacar las características que tienen una correlación mayor a un umbral dado. Para eso, definimos el umbral y volvemos a sacar la matriz de correlación, pero esta vez con los valores absolutos (un valor de correlación = -1 indica una alta correlación negativa, con lo que también deberíamos tenerlo en cuenta).
umbral_corr = 0.7 corr_matrix = X_train.corr().abs()
Para seleccionar las características que tienen una correlación mayor que nuestro umbral, vamos a usar un par de funciones de numpy:
Por ejemplo, si queremos crear una matriz de 5×5 con los elementos del triángulo superior = 1 y el resto a 0:
np.triu(np.ones((5, 5)), k=1)
array([[0., 1., 1., 1., 1.], [0., 0., 1., 1., 1.], [0., 0., 0., 1., 1.], [0., 0., 0., 0., 1.], [0., 0., 0., 0., 0.]])
También podemos pasar los elementos a booleanos:
np.triu(np.ones((5, 5)), k=1).astype(np.bool)
array([[False, True, True, True, True], [False, False, True, True, True], [False, False, False, True, True], [False, False, False, False, True], [False, False, False, False, False]])
Ahora podemos combinar ambas matrices (la de correlación y la que hemos creado) con el método where de pandas para quedarnos sólo con los valores del triángulo superior de la matriz de correlación (el triángulo inferior contiene los mismos valores, con lo que no hace falta tenerlos en cuenta).
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
Al final, tendremos una matriz parecida a ésta:
upper
Lo último será seleccionar aquellas columnas que contengan algún valor por encima del umbral dado:
to_drop = [column for column in upper.columns if any(upper[column] > umbral_corr)] print(to_drop)
['flavanoids', 'od280/od315_of_diluted_wines']
Ahora ya podemos eliminar las características:
# Drop features X_train = X_train.drop(columns = to_drop, axis=1) X_test = X_test.drop(columns = to_drop, axis=1) X_train.shape, X_test.shape
((124, 11), (54, 11))