1.13. Selección de características

Las clases del módulo sklearn.feature_selection pueden utilizarse para la selección de características / reducción de la dimensionalidad en conjuntos de muestras, ya sea para mejorar las puntuaciones de exactitud de los estimadores o para aumentar su rendimiento en conjuntos de datos de muy alta dimensión.

1.13.1. Remover características con varianza baja

VarianceThreshold es una aproximación simple a la selección de características. Elimina todas las características cuya varianza no alcanza un determinado umbral. Por defecto, elimina todas las características de varianza cero, es decir, las características que tienen el mismo valor en todas las muestras.

Por ejemplo, supongamos que tenemos un conjunto de datos con características booleanas y queremos eliminar todas las características que sean uno o cero (activadas o desactivadas) en más del 80% de las muestras. Las características booleanas son variables aleatorias de Bernoulli, y la varianza de dichas variables viene dada por

\[\mathrm{Var}[X] = p(1 - p)\]

de manera que podamos seleccionar utilizando el umbral .8 * (1 - .8):

>>> from sklearn.feature_selection import VarianceThreshold
>>> X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
>>> sel = VarianceThreshold(threshold=(.8 * (1 - .8)))
>>> sel.fit_transform(X)
array([[0, 1],
       [1, 0],
       [0, 0],
       [1, 1],
       [1, 0],
       [1, 1]])

Como se esperaba, VarianceThreshold ha eliminado la primera columna, que tiene una probabilidad de \(p = 5/6 > .8\) de contener un cero.

1.13.2. Selección de características univariantes

La selección de características univariantes funciona mediante la selección de las mejores características basadas en pruebas estadísticas univariantes. Puede verse como un paso de preprocesamiento de un estimador. Scikit-learn expone las rutinas de selección de características como objetos que implementan el método transform:

  • SelectKBest elimina todas las características excepto las de mayor puntuación de :math:`k

  • SelectPercentile elimina todas las características excepto las del porcentaje de puntuación más alto especificado por el usuario

  • aplicando pruebas estadísticas univariantes comunes para cada característica: tasa de falsos positivos SelectFpr, tasa de falsos descubrimientos SelectFdr, o error por familia SelectFwe.

  • GenericUnivariateSelect permite realizar la selección de características univariantes con una estrategia configurable. Permite seleccionar la mejor estrategia de selección univariante con el estimador de búsqueda de hiperparámetros.

Por ejemplo, podemos realizar una prueba \(\chi^2\) a las muestras para recuperar sólo las dos mejores características de la siguiente manera:

>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.feature_selection import chi2
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> X_new = SelectKBest(chi2, k=2).fit_transform(X, y)
>>> X_new.shape
(150, 2)

Estos objetos toman como entrada una función de puntuación que devuelve puntuaciones univariantes (univariate scores) y valores p (o sólo puntuaciones para SelectKBest y SelectPercentile):

Los métodos basados en la prueba F estiman el grado de dependencia lineal entre dos variables aleatorias. Por otro lado, los métodos de información mutua pueden capturar cualquier tipo de dependencia estadística, pero al no ser paramétricos, requieren más muestras para una estimación precisa.

Selección de características con datos dispersos

Si utiliza datos dispersos (es decir, datos representados como matrices dispersas), chi2, mutual_info_regression, mutual_info_classif se ocuparán de los datos sin hacerlos densos.

Advertencia

Ten cuidado de no utilizar una función de puntuación de regresión con un problema de clasificación, ya que obtendrás resultados inservibles.

1.13.3. Eliminación recursiva de características

Dado un estimador externo que asigna pesos a las características (por ejemplo, los coeficientes de un modelo lineal), el objetivo de la eliminación recursiva de características (RFE) es seleccionar características considerando recursivamente conjuntos cada vez más pequeños de características. En primer lugar, el estimador se entrena con el conjunto inicial de características y la importancia de cada una de ellas se obtiene a través de algún atributo específico (como coef_, feature_importances_) u otro invocable. A continuación, las características menos importantes se eliminan del conjunto actual de características. Este procedimiento se repite recursivamente en el conjunto reducido (pruned) hasta que se alcanza el número deseado de características a seleccionar.

RFECV realiza la RFE en un bucle de validación cruzada para encontrar el número óptimo de características.

Ejemplos:

1.13.4. Selección de características mediante SelectFromModel

SelectFromModel es un metatransformador que puede utilizarse junto con cualquier estimador de la importancia de cada característica a través de un atributo específico (tales como coef_, feature_importances_) o invocable después del ajuste. Las características se consideran poco importantes y se eliminan si la importancia correspondiente de los valores de las características está por debajo del parámetro threshold proporcionado. Aparte de especificar el umbral numéricamente, hay heurísticas integradas que permiten encontrar un umbral utilizando un argumento de cadena. Las heurísticas disponibles son «mean», «median» y múltiplos flotantes de éstas como «0.1*mean». En combinación con el criterio threshold, se puede utilizar el parámetro max_features para establecer un límite en el número de características a seleccionar.

Para ver ejemplos de cómo se debe utilizar, consulta las secciones que siguen.

1.13.4.1. Selección de características basada en L1

Linear models penalizados con la norma L1 tienen soluciones dispersas: muchos de sus coeficientes estimados son cero. Cuando el objetivo es reducir la dimensionalidad de los datos para utilizarlos con otro clasificador, pueden utilizarse junto con SelectFromModel para seleccionar los coeficientes no nulos. En particular, los estimadores dispersos útiles para este propósito son los Lasso para la regresión, y de LogisticRegression y LinearSVC para la clasificación:

>>> from sklearn.svm import LinearSVC
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> lsvc = LinearSVC(C=0.01, penalty="l1", dual=False).fit(X, y)
>>> model = SelectFromModel(lsvc, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape
(150, 3)

Con las SVM y la regresión logística, el parámetro C controla la dispersión: cuanto menor sea C, menos características serán seleccionadas. Con Lasso, cuanto mayor sea el parámetro alfa, menos características se seleccionarán.

Ejemplos:

Recuperación del L1 y muestreo con compresión (compressive sensing)

Para una buena elección de alfa, el Lasso puede recuperar completamente el conjunto exacto de variables no nulas utilizando sólo unas pocas observaciones, siempre que se cumplan ciertas condiciones específicas. En particular, el número de muestras debe ser «suficientemente grande», o los modelos L1 se comportarán de forma aleatoria, en donde » suficientemente grande» depende del número de coeficientes no nulos, del logaritmo del número de características, de la cantidad de ruido, del menor valor absoluto de los coeficientes no nulos y de la estructura de la matriz de diseño X. Además, la matriz de diseño debe mostrar ciertas propiedades específicas, como no estar demasiado correlacionada.

No hay una regla general para seleccionar un parámetro alfa para la recuperación de coeficientes distintos de cero. Puede establecerse mediante validación cruzada (LassoCV o LassoLarsCV), aunque esto puede conducir a modelos insuficientemente penalizados: la inclusión de un pequeño número de variables no relevantes no es perjudicial para la puntuación de la predicción. BIC (LassoLarsIC) tiende, por el contrario, a establecer valores altos de alfa.

Referencia Richard G. Baraniuk «Compressive Sensing», IEEE Signal Processing Magazine [120] July 2007 http://users.isr.ist.utl.pt/~aguiar/CS_notes.pdf

1.13.4.2. Selección de características basada en árboles

Los estimadores basados en árboles (ver el módulo sklearn.tree y el bosque de árboles en el módulo sklearn.ensemble) pueden utilizarse para calcular la importancia de características basadas en impurezas, que a su vez pueden utilizarse para descartar características irrelevantes (cuando se combinan con el metatransformador SelectFromModel):

>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.datasets import load_iris
>>> from sklearn.feature_selection import SelectFromModel
>>> X, y = load_iris(return_X_y=True)
>>> X.shape
(150, 4)
>>> clf = ExtraTreesClassifier(n_estimators=50)
>>> clf = clf.fit(X, y)
>>> clf.feature_importances_  
array([ 0.04...,  0.05...,  0.4...,  0.4...])
>>> model = SelectFromModel(clf, prefit=True)
>>> X_new = model.transform(X)
>>> X_new.shape               
(150, 2)

Ejemplos:

1.13.5. Selección secuencial de características

La selección secuencial de características [sfs] (SFS) está disponible en el transformador SequentialFeatureSelector. SFS puede funcionar hacia adelante (forward) o hacia atrás (backward):

Forward-SFS es un procedimiento ambicioso (greedy) que encuentra de forma iterativa la mejor característica nueva para añadir al conjunto de características seleccionadas. Concretamente, empezamos con cero características y encontramos la que maximiza una puntuación validada de forma cruzada cuando se entrena un estimador con esta única característica. Una vez seleccionada esa primera característica, repetimos el procedimiento añadiendo una nueva característica al conjunto de características seleccionadas. El procedimiento se detiene cuando se alcanza el número deseado de características seleccionadas, determinado por el parámetro n_features_to_select.

Backward-SFS sigue la misma idea, pero funciona en la dirección opuesta: en lugar de empezar sin ninguna característica y añadirla codiciosamente, empezamos con todas las características y eliminamos codiciosamente las características del conjunto. El parámetro direction controla si se utiliza el SFS hacia adelante o hacia atrás.

En general, la selección hacia adelante (forward) y la selección hacia atrás (backward) no dan resultados equivalentes. Además, una puede ser mucho más rápida que la otra dependiendo del número de características seleccionadas que se soliciten: si tenemos 10 características y queremos que se seleccionen 7, la selección hacia delante necesitaría realizar 7 iteraciones mientras que la selección hacia atrás sólo necesitaría llevar a cabo 3.

SFS difiere de RFE y SelectFromModel en que no requiere que el modelo subyacente exponga un atributo coef_ o feature_importances_. Sin embargo, puede ser más lento, en comparación con los otros enfoques, ya que es necesario evaluar más modelos. Por ejemplo, en la selección hacia atrás, la iteración que va de m características a m - 1 características utilizando la validación cruzada de k partes requiere el ajuste de m * k modelos, mientras que RFE sólo requeriría un único ajuste, y SelectFromModel siempre hace un único ajuste y no requiere iteraciones.

1.13.6. Selección de rasgos como parte de un pipeline

La selección de características se utiliza generalmente como un paso de preprocesamiento antes de realizar el aprendizaje propiamente dicho. La forma recomendada de hacer esto en scikit-learn es utilizar un Pipeline:

clf = Pipeline([
  ('feature_selection', SelectFromModel(LinearSVC(penalty="l1"))),
  ('classification', RandomForestClassifier())
])
clf.fit(X, y)

En este fragmento utilizamos un LinearSVC junto con SelectFromModel para evaluar la importancia de las características y seleccionar las más relevantes. A continuación, se entrena un RandomForestClassifier en la salida transformada, es decir, utilizando sólo las características relevantes. Puedes realizar operaciones similares con los otros métodos de selección de características y también con clasificadores que proporcionan una forma de evaluar la importancia de las características, por supuesto. Puedes consultar los ejemplos de Pipeline para más detalles.