Artículos / Machine Learning

[ Machine Learning ]sklearn-genetic-optPythonscikit-learnfeature selection

Selecciona características con sklearn-genetic-opt

Usa GAFeatureSelectionCV 0.14.0 con escalado dentro de cada fold, revisa las variables seleccionadas y evalúa pipelines sobre datos de prueba separados.

16 de abril de 2026·5 min de lectura
Selecciona características con sklearn-genetic-opt

GAFeatureSelectionCV evalúa subconjuntos de columnas mediante validación cruzada. Su resultado depende del estimador, la métrica, los datos y el presupuesto de búsqueda. Este ejemplo usa sklearn-genetic-opt para seleccionar variables, comparar dos líneas base y ajustar un SVM sobre el subconjunto elegido. Cada valor mostrado se calcula al ejecutar el código.

Versiones y ejecución

Los cuatro bloques Python forman un archivo, selection_demo.py, en ese orden. Se probaron con Python 3.12, sklearn-genetic-opt 0.14.0, scikit-learn 1.9.1 y NumPy 2.5.3. Tras guardar los bloques, ejecuta estos comandos PowerShell. Pip resuelve las demás dependencias; para un release fija el entorno completo.

powershell
py -3.12 -m venv .venv
& .\.venv\Scripts\python.exe -m pip install sklearn-genetic-opt==0.14.0 scikit-learn==1.9.1 numpy==2.5.3
& .\.venv\Scripts\python.exe selection_demo.py

Separa los datos crudos; escala dentro de cada fold

El dataset incluido tiene 569 observaciones y 30 columnas. Separa primero la matriz cruda. Al poner StandardScaler dentro del Pipeline del estimador, cada fold de cada candidato aprende el escalado sólo con sus filas de entrenamiento. El refit final aprende con todas las filas de entrenamiento; las filas reservadas para evaluación siguen separadas.

Ajustar el escalador antes del split hace que las mediciones de prueba influyan en el entrenamiento. Ajustarlo sobre toda la matriz de entrenamiento antes de CV también expone las mediciones de cada fold de validación. La guía de fuga de datos de scikit-learn explica la separación y el uso del pipeline.

python
from functools import partial
import numpy as np
from sklearn.base import clone
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectKBest, mutual_info_classif
from sklearn.metrics import accuracy_score
from sklearn.model_selection import StratifiedKFold, cross_val_score, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn_genetic import (
    EvolutionConfig, GAFeatureSelectionCV, GASearchCV,
    OptimizationConfig, RuntimeConfig,
)
from sklearn_genetic.space import Continuous

data = load_breast_cancer()
X, y = data.data, data.target
feature_names = data.feature_names
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)
cv = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)
estimator = Pipeline([
    ("scale", StandardScaler()),
    ("svc", SVC(kernel="rbf", C=1.0, gamma="scale")),
])
evolution = EvolutionConfig(population_size=8, generations=4)
runtime = RuntimeConfig(n_jobs=1, verbose=False, error_score="raise")
optimization = OptimizationConfig(diversity_control=False)
selector = GAFeatureSelectionCV(
    estimator=estimator, cv=cv, scoring="accuracy",
    evolution_config=evolution, runtime_config=runtime,
    optimization_config=optimization, random_state=42,
)
selector.fit(X_train, y_train)

Ocho individuos, cuatro generaciones y tres folds forman una demostración pequeña. Las evaluaciones iniciales, descendientes y repeticiones en caché afectan el número real de ajustes; multiplicar población por generaciones no establece un total exacto. Esta configuración desactiva el control de diversidad para aislar la búsqueda básica y usa un job. Aumentar el presupuesto añade trabajo y puede cambiar el resultado; no garantiza el óptimo global.

Revisa la máscara y su score de búsqueda

support_ conserva el orden de las columnas originales. transform() retira las columnas descartadas y mantiene los valores y el orden de las restantes. El pipeline ajustado se encarga del escalado. selector.predict(X_test) aplica su máscara internamente; best_estimator_ espera una matriz ya seleccionada.

python
selected_features = feature_names[selector.support_]
print("Selected features:", selected_features.tolist())
print("Feature count:", int(selector.support_.sum()))
X_train_selected = selector.transform(X_train)
X_test_selected = selector.transform(X_test)
print("Training shapes:", X_train.shape, X_train_selected.shape)

# Match the chosen mask to its actual public CV results row.
selected_row = next(
    index for index, mask in enumerate(selector.cv_results_["features"])
    if np.array_equal(mask, selector.support_)
)
search_cv_score = float(selector.cv_results_["mean_test_score"][selected_row])
print(f"Selected-mask search CV: {search_cv_score:.4f}")

En la versión 0.14.0, best_score_ del selector pertenece a la validación opcional de selección final (final_selection=True). Este ejemplo usa la selección de búsqueda predeterminada y lee la fila de la máscara correspondiente en cv_results_. El valor CV impreso es un objetivo usado para elegir la máscara; no es una estimación insesgada de la accuracy futura del flujo elegido. La cantidad y los nombres de las variables dependen de los datos, la búsqueda y las versiones.

Líneas base y una segunda etapa de ajuste

La línea base con todas las variables usa el mismo pipeline SVM. La línea base de filtro selecciona diez columnas mediante información mutua dentro de cada fold, después escala y ajusta. Diez es una elección de demostración; decide esos ajustes con datos de entrenamiento. El filtro evalúa columnas individualmente; el wrapper evalúa subconjuntos con el estimador. Sus costos son distintos y cualquiera puede funcionar mejor en un dataset concreto.

La segunda búsqueda ajusta svc__C y svc__gamma del pipeline. La máscara queda fijada desde la primera búsqueda y sólo entran filas de entrenamiento al ajuste. Las dos etapas siguientes forman un flujo condicionado: los folds del ajuste comparten una máscara elegida previamente con todo el entrenamiento. Sus scores CV ayudan a elegir parámetros; no estiman imparcialmente el proceso completo de selección más ajuste. Para una comparación insesgada, repite todo ese flujo dentro del entrenamiento de folds externos o evalúa un holdout separado, sin tocarlo hasta congelar las decisiones.

python
all_features = clone(estimator)
filter_model = Pipeline([
    ("select", SelectKBest(partial(mutual_info_classif, random_state=42), k=10)),
    ("scale", StandardScaler()),
    ("svc", SVC(kernel="rbf", C=1.0, gamma="scale")),
])
for name, model in [("all_features", all_features), ("filter_10", filter_model)]:
    scores = cross_val_score(
        model, X_train, y_train, cv=cv, scoring="accuracy",
        n_jobs=1, error_score="raise",
    )
    print(f"{name} CV: {scores.mean():.4f} +/- {scores.std():.4f}")
    model.fit(X_train, y_train)

hp_search = GASearchCV(
    estimator=clone(estimator),
    param_grid={
        "svc__C": Continuous(0.1, 10.0, distribution="log-uniform"),
        "svc__gamma": Continuous(0.01, 1.0, distribution="log-uniform"),
    },
    cv=cv, scoring="accuracy", evolution_config=evolution,
    runtime_config=runtime, optimization_config=optimization, random_state=42,
)
hp_search.fit(X_train_selected, y_train)
print("Tuned parameters:", hp_search.best_params_)
print(f"Fixed-mask tuning CV: {hp_search.best_score_:.4f}")

Las dos etapas pueden costar más que otros métodos. Registra ajustes reales, tiempo y semillas al comparar presupuestos. Reducir las columnas por sí solo no demuestra un score mejor ni un costo total menor.

Reporta la evaluación después de las decisiones de entrenamiento

Los cuatro flujos ya se ajustaron sin usar X_test o y_test. Ejecuta este reporte final después de elegirlos con evidencia del entrenamiento. Cambiar repetidamente ajustes según estos resultados convertiría el holdout en datos de desarrollo. Estas son accuracies sobre una partición de un pequeño dataset incluido, sin declarar un ganador ni garantías de despliegue.

python
holdout_scores = {
    "all_features": float(accuracy_score(y_test, all_features.predict(X_test))),
    "filter_10": float(accuracy_score(y_test, filter_model.predict(X_test))),
    "genetic": float(accuracy_score(y_test, selector.predict(X_test))),
    "genetic_tuned": float(accuracy_score(
        y_test, hp_search.predict(X_test_selected)
    )),
}
for name, score in holdout_scores.items():
    print(f"{name}: {score:.4f}")

Continúa con búsqueda de hiperparámetros o probabilidades adaptativas. El código publicado del selector describe los atributos usados aquí; la guía de pipelines de scikit-learn explica los nombres de pasos y prefijos de parámetros.

¿Vas a construir una plataforma de IA o de datos?

Si necesitas adaptar este enfoque a tu sistema, cuéntame qué datos tienes y qué decisión técnica necesitas resolver.

Ver todos los proyectos