Boruta #
Vamos a seleccionar características utilizando Boruta. El código en este bloque es un ejemplo directo del uso de Boruta.
Referencia:Kursa, Miron B., and Witold R. Rudnicki. "Feature selection with the Boruta package." Journal of statistical software 36 (2010): 1-13.
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from boruta import BorutaPy
# FIXME
np.random.seed(777)
np.int = int
np.float = float
np.bool = bool
# Cargar los datos X e y
X = pd.read_csv("examples/test_X.csv", index_col=0).values
y = pd.read_csv("examples/test_y.csv", header=None, index_col=0).values
y = y.ravel()
# Definir un clasificador Random Forest utilizando todos los núcleos disponibles
# y muestreo proporcional a las etiquetas de y
rf = RandomForestClassifier(n_jobs=-1, class_weight="balanced", max_depth=5)
# Definir el método de selección de características Boruta
feat_selector = BorutaPy(rf, n_estimators="auto", verbose=2, random_state=1)
# Encontrar todas las características relevantes - se deberían seleccionar 5 características
feat_selector.fit(X, y)
# Comprobar las características seleccionadas - las primeras 5 características deberían ser seleccionadas
feat_selector.support_
# Comprobar el ranking de las características
feat_selector.ranking_
# Aplicar transform() a X para reducirlo a las características seleccionadas
X_filtered = feat_selector.transform(X)
Iteration: 1 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 2 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 3 / 100
Confirmed: 0
Tentative: 10
BorutaPy finished running.
Iteration: 9 / 100
Confirmed: 5
Tentative: 0
Rejected: 5
Experimentos con Datos Artificiales #
from sklearn.datasets import make_classification
from xgboost import XGBClassifier
def fs_by_boruta(model, X, y):
feat_selector = BorutaPy(model, n_estimators="auto", verbose=2, random_state=1)
feat_selector.fit(X, y)
X_filtered = feat_selector.transform(X)
if X.shape[1] == X_filtered.shape[1]:
print("No se encontraron características innecesarias")
else:
print("Se eliminaron características innecesarias")
print(f"{X.shape[1]} --> {X_filtered.shape[1]}")
return X_filtered
No se elimina ninguna característica si todas son necesarias #
X, y = make_classification(
n_samples=1000,
n_features=10,
n_informative=10,
n_redundant=0,
n_repeated=0,
n_classes=2,
random_state=0,
shuffle=False,
)
model = XGBClassifier(max_depth=4)
fs_by_boruta(model, X, y)
Iteration: 1 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 2 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 3 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 4 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 5 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 6 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 7 / 100
Confirmed: 0
Tentative: 10
Rejected: 0
Iteration: 8 / 100
Confirmed: 10
Tentative: 0
Rejected: 0
BorutaPy finished running.
Iteration: 9 / 100
Confirmed: 10
Tentative: 0
Rejected: 0
不用な特徴は見つかりませんでした
array([[ 0.38760058, -0.4398061 , 1.0103586 , ..., -2.11674403,
-3.59368321, -0.43265007],
[-2.18745511, -2.45701675, 1.99758878, ..., 1.16128752,
-1.92766999, 3.18705784],
[ 3.98304273, 0.06250274, -1.31136045, ..., 1.45498409,
-4.17178063, -2.21695578],
...,
[-0.44293666, 3.25707522, -0.50633794, ..., -0.72410483,
-1.5420989 , 0.75991518],
[-1.12641706, -0.48636924, 0.92918889, ..., -1.01001779,
-2.69280573, -3.47050681],
[-2.3936814 , 1.44048113, 1.95832126, ..., -5.15104933,
-1.02766442, 1.4853396 ]])
Se eliminan las características innecesarias #
Crearemos un conjunto de datos con 100 características, de las cuales solo 10 son útiles, para observar cuántas características innecesarias pueden ser eliminadas.
La documentación de sklearn.datasets.make_classification especifica:
Sin mezclar, las características en
X
se apilan horizontalmente en el siguiente orden: lasn_informative
características principales, seguidas porn_redundant
combinaciones lineales de las características informativas, seguidas porn_repeated
duplicados, seleccionados al azar con reemplazo de las características informativas y redundantes. Las características restantes se rellenan con ruido aleatorio. Por lo tanto, sin mezclar, todas las características útiles están contenidas en las columnasX[:, :n_informative + n_redundant + n_repeated]
.
Por lo tanto, verificaremos que las primeras 10 columnas, que corresponden a las características útiles, no sean eliminadas durante el proceso.
X, y = make_classification(
n_samples=2000,
n_features=100,
n_informative=10,
n_redundant=0,
n_repeated=0,
n_classes=2,
random_state=0,
shuffle=False,
)
model = XGBClassifier(max_depth=5)
X_b = fs_by_boruta(model, X, y)
Iteration: 1 / 100
Confirmed: 0
Tentative: 100
Rejected: 0
Iteration: 2 / 100
…
BorutaPy finished running.
Iteration: 100 / 100
Confirmed: 10
Tentative: 1
Rejected: 88
不用な特徴を削除しました
100 --> 10
Verificar que las características útiles permanecen en los datos después del filtrado #
Si el filtrado funciona como se espera, las primeras 10 columnas, que corresponden a características útiles, deberían permanecer intactas en los datos procesados.
X[:, :10] == X_b[:, :10]
array([[ True, True, True, ..., True, True, True],
[ True, True, True, ..., True, True, True],
[ True, True, True, ..., True, True, True],
...,
[ True, True, True, ..., True, True, True],
[ True, True, True, ..., True, True, True],
[ True, True, True, ..., True, True, True]])