scikit-learnMiddleCoding

Как работают VotingClassifier и StackingClassifier в scikit-learn?

VotingClassifier объединяет предсказания через голосование (hard — большинство меток, soft — усреднение вероятностей); StackingClassifier обучает мета-модель на out-of-fold предсказаниях базовых моделей через cross-validation, что даёт лучшее качество ценой большего времени обучения.

VotingClassifier и StackingClassifier в scikit-learn

Оба класса реализуют ансамблевые методы, но используют разные стратегии объединения предсказаний базовых моделей.

VotingClassifier

Объединяет предсказания нескольких моделей через голосование. Два режима: hard (мажоритарное голосование по меткам классов) и soft (усреднение вероятностей).

from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Hard voting: мажоритарное голосование по предсказанным классам
voting_hard = VotingClassifier(
    estimators=[
        ('lr', LogisticRegression(random_state=42)),
        ('dt', DecisionTreeClassifier(max_depth=5, random_state=42)),
        ('svm', SVC(kernel='rbf', random_state=42)),  # SVC без probability=True
    ],
    voting='hard',
)
voting_hard.fit(X_train, y_train)
print(f'Hard voting accuracy: {accuracy_score(y_test, voting_hard.predict(X_test)):.3f}')

# Soft voting: усреднение вероятностей (обычно лучше hard)
voting_soft = VotingClassifier(
    estimators=[
        ('lr', LogisticRegression(random_state=42)),
        ('dt', DecisionTreeClassifier(max_depth=5, random_state=42)),
        # SVC нужен probability=True для soft voting
        ('svm', SVC(kernel='rbf', probability=True, random_state=42)),
    ],
    voting='soft',
    weights=[2, 1, 1],  # логистическая регрессия имеет вес 2
)
voting_soft.fit(X_train, y_train)
print(f'Soft voting accuracy: {accuracy_score(y_test, voting_soft.predict(X_test)):.3f}')

# Доступ к отдельным estimators
print(voting_soft.named_estimators_['lr'].coef_.shape)

StackingClassifier

Обучает мета-модель (final_estimator) на предсказаниях базовых моделей (first level). Базовые модели обучаются через cross-validation, чтобы мета-модель обучалась на out-of-fold предсказаниях.

from sklearn.ensemble import StackingClassifier, RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
import numpy as np

# Базовые модели (first level)
base_estimators = [
    ('rf', RandomForestClassifier(n_estimators=100, random_state=42)),
    ('gb', GradientBoostingClassifier(n_estimators=100, random_state=42)),
    ('lr', LogisticRegression(max_iter=1000, random_state=42)),
]

# Мета-модель (second level) обучается на предсказаниях base estimators
stacking = StackingClassifier(
    estimators=base_estimators,
    final_estimator=LogisticRegression(),  # мета-классификатор
    cv=5,                                   # кросс-валидация для out-of-fold предсказаний
    stack_method='predict_proba',           # передаём вероятности, не метки
    passthrough=False,                      # True: добавить исходные X к мета-признакам
    n_jobs=-1,
)

stacking.fit(X_train, y_train)
print(f'Stacking accuracy: {accuracy_score(y_test, stacking.predict(X_test)):.3f}')

# CV оценка
scores = cross_val_score(stacking, X_train, y_train, cv=5, scoring='accuracy')
print(f'CV accuracy: {scores.mean():.3f} ± {scores.std():.3f}')

# Получить предсказания первого уровня
transform_output = stacking.transform(X_test)  # мета-признаки
print(f'Meta-features shape: {transform_output.shape}')  # (n_samples, n_classes * n_estimators)

Когда что использовать

  • VotingClassifier: быстрый ансамбль разнородных моделей, когда модели примерно одинаковы по качеству. Простота и интерпретируемость.
  • StackingClassifier: когда хотите извлечь максимальное качество; мета-модель учится, когда доверять каждой базовой модели. Медленнее из-за CV при fit.
  • Stacking обычно превосходит Voting на Kaggle, но требует большего датасета и времени обучения.

Подводные камни

  • Использовать soft voting с моделью без predict_proba (SVC без probability=True) — ValueError при fit.
  • Не обеспечить разнообразие базовых моделей в VotingClassifier — 3 одинаковых LogisticRegression не лучше одного.
  • В StackingClassifier использовать cv=None (prefit estimators) — мета-модель обучается на train predictions, что вызывает overfitting мета-уровня.
  • Игнорировать passthrough=True в Stacking: иногда добавление исходных признаков к мета-признакам значительно улучшает результат.
  • Обучать Stacking без достаточного размера датасета — мета-модель переобучается при < 1000 примеров.
  • Не использовать n_jobs=-1 в StackingClassifier — обучение 5 fold × N моделей последовательно занимает в разы дольше.
  • Не проверять, что базовые модели обучены на одинаковых признаках — проблема при использовании разных preprocessing для разных моделей вне единого Pipeline.
  • Смешивать Stacking с GridSearchCV без осторожности: кросс-валидация внутри Stacking nested в outer CV — экспоненциальный рост времени.

Common mistakes

  • Объяснять voting and stacking только синтаксисом без shape, dtype, состояния или режима выполнения.
  • Игнорировать leakage, воспроизводимость, пустые входы и скрытые копии данных.
  • Не проверять production-симптомы: latency, память, ретраи, дрейф качества и несовпадение версий.

What the interviewer is testing

  • Может ли связать voting and stacking с реальным контрактом входов и выходов.
  • Упоминает ли тесты, метрики, reproducibility и диагностику ошибок.
  • Видит ли различие между demo-кодом в ноутбуке и production-пайплайном.

Sources

Related topics