Feature Names в Scikit-learn: как не потерять названия колонок

Раздел: Data Science -> Scikit-learn

Управление именами признаков в Scikit Learn

Имена признаков (feature names) играют ключевую роль при интерпретации моделей, отладке пайплайнов и визуализации. В Scikit Learn начиная с версии 0.23 появилась единая система работы с названиями колонок через метод get_feature_names_out(). Рекомендуется передавать данные в виде pandas DataFrame, чтобы библиотека автоматически сохраняла имена.

Основной подход: обучение модели или трансформера на DataFrame, после чего доступны атрибуты feature_names_in_ (названия исходных признаков) и метод get_feature_names_out() (названия после преобразования).

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler

df = pd.DataFrame({
    'age': [25, 30, 35],
    'income': [50000, 60000, 70000],
    'city': ['Moscow', 'SPb', 'Kazan']
})
y = [0, 1, 0]

# Модель, сохраняющая имена
rf = RandomForestClassifier()
rf.fit(df, y)
print(rf.feature_names_in_)  # ['age', 'income', 'city']

# Трансформер с get_feature_names_out
scaler = StandardScaler()
X_scaled = scaler.fit_transform(df[['age','income']])  # потеря имён
# Получаем имена 
print(scaler.get_feature_names_out(['age','income']))  # ['age', 'income']

библиотеки для машинного обучения python (библиотеки для машинного обучения в python (scikit-learn, tensorflow, pytorch))

Если применить к DataFrame, метод возвращает те же имена. В случае кодирования категорий (OneHotEncoder) имена создаются автоматически.

Как получить имена признаков после ColumnTransformer?

Часто используется ColumnTransformer для разных типов колонок. После вызова fit() доступен get_feature_names_out(), возвращающий результирующие имена.

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder

ct = ColumnTransformer([
    ('numeric', StandardScaler(), ['age','income']),
    ('categ', OneHotEncoder(), ['city'])
])
X_trans = ct.fit_transform(df)
print(ct.get_feature_names_out())
# ['numeric__age', 'numeric__income', 'categ__Moscow', 'categ__SPb', 'categ__Kazan']

Feature names python (имена признаков в python)

Типичная ошибка: использование старых версий sklearn (<0.23), где get_feature_names_out() отсутствует. Решение: обновить библиотеку или вручную задавать имена через список.

Как задать имена признаков вручную?

Когда данные не являются DataFrame (numpy массив), имена можно передать через параметр feature_names_out у некоторых трансформеров (например, FunctionTransformer) или после преобразования задать список вручную.

import numpy as np
from sklearn.preprocessing import PolynomialFeatures

X = np.array([[1, 2], [3, 4]])
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
# По умолчанию имена генерируются как 'x0', 'x1', 'x0^2', 'x0 x1', 'x1^2'
names = poly.get_feature_names_out(['alpha', 'beta'])
print(names)  # ['alpha', 'beta', 'alpha^2', 'alpha beta', 'beta^2']

искусственный интеллект на языке python (искусственный интеллект на python)

Как сохранить имена признаков в Pipeline?

При использовании Pipeline имена можно получить после fit(), если все шаги поддерживают get_feature_names_out(). Результат будет комбинированным.

from sklearn.pipeline import Pipeline

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('poly', PolynomialFeatures(degree=2, include_bias=False))
])
pipe.fit(df[['age','income']])
print(pipe.get_feature_names_out())  # ['age', 'income', 'age^2', 'age income', 'income^2']
- создание нейросетей на python (создание нейронных сетей на python (tensorflow, pytorch))
- библиотека scikit python (библиотека scikit-learn для python)
- задачи машинного обучения python (задачи машинного обучения на python)

Расширенные примеры работы с именами признаков

Пример 1: GridSearchCV с отслеживанием имён

При поиске гиперпараметров признаки могут меняться. Использование DataFrame гарантирует, что имена сохранятся внутри модели.

Пример
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier

param_grid = {'max_depth': [3,5]}
gs = GridSearchCV(DecisionTreeClassifier(), param_grid, cv=2)
gs.fit(df, y)
best_model = gs.best_estimator_
print(best_model.feature_names_in_)
['age', 'income', 'city']

Пример 2: Восстановление имён после PCA

PCA теряет исходные имена, так как создаёт новые компоненты. Однако можно задать свои имена.

Пример
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
principal_components = pca.fit_transform(df[['age','income','city_encoded']])
# Создаём имена вручную
feature_names = [f'PC{i+1}' for i in range(principal_components.shape[1])]
print(feature_names)  # ['PC1', 'PC2']
['PC1', 'PC2']

Пример 3: Функция трансформации с сохранением имён

FunctionTransformer позволяет задать пользовательскую функцию и указать feature_names_out.

Пример
from sklearn.preprocessing import FunctionTransformer

def log_transform(X):
    return np.log1p(X)

transformer = FunctionTransformer(
    func=log_transform,
    feature_names_out=lambda self, names: [f'log_{n}' for n in names]
)
X_log = transformer.fit_transform(df[['age','income']])
print(transformer.get_feature_names_out(['age','income']))
['log_age', 'log_income']

Пример 4: Обработка категорий с OneHotEncoder

После кодирования имена содержат имя признака и значение категории.

Пример
ohe = OneHotEncoder(sparse_output=False, feature_name_combiner='concat')
encoded = ohe.fit_transform(df[['city']])
print(ohe.get_feature_names_out(['city']))
['city_Moscow', 'city_SPb', 'city_Kazan']

Пример 5: Проблема с Pipeline и пайплайном без get_feature_names_out

Если один из шагов не поддерживает этот метод (например, старый трансформер), возникает ошибка. Решение: обернуть такой шаг в FunctionTransformer с явным указанием имён или использовать FeatureUnion.

Пример
from sklearn.pipeline import FeatureUnion

# Предположим, у нас есть кастомный трансформер без get_feature_names_out
# class OldTransformer: 
#     def fit(self, X, y=None): return self
#     def transform(self, X): return X * 2

# Решение: обёртка
class NamedTransformer:
    def __init__(self, names):
        self.names = names
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X * 2
    def get_feature_names_out(self, input_features=None):
        return self.names

union = FeatureUnion([
    ('old', NamedTransformer(['a','b'])),
    ('scaler', StandardScaler())
])
X_tr = union.fit_transform(df[['age','income']])
print(union.get_feature_names_out())  # ['old__a', 'old__b', 'scaler__age', 'scaler__income']

Имена признаков в Python - comments

En
Feature names python (python)