Вопрос или проблема
Я попытался создать класс Python, CustomStackingClassifier(), чтобы реализовать метод стекинга в ансамблевом машинном обучении. В этой реализации выход базовых классификаторов задается как прогнозируемые вероятности, а для обучения модели используется StratifiedKFold. Входная матрица для мета-классификатора имеет размерность (образцы, модели * классы).
Этот код по сути вручную воспроизводит функциональность sklearn.ensemble.StackingClassifier(). Однако после тестирования его на наборе данных о вине и сравнения результатов между двумя методами я обнаружил расхождения. Несмотря на то, что потратил на это много времени, я не смог выявить проблему. Буду очень признателен за любую помощь или идеи от сообщества. Большое спасибо!
Надеюсь выяснить, есть ли логическая проблема с CustomStackingClassifier(). Если проблема есть, буду признателен за рекомендации и предложения по исправлению. Если реализация правильная, почему она показывает различия в результатах по сравнению с sklearn.ensemble.StackingClassifier()?
Важно отметить, что гиперпараметры и random_state для как базовых классификаторов, так и мета-классификатора фиксированы, так что эти факторы можно исключить как причину.
Код следующий:
class CustomStackingClassifier(BaseEstimator, ClassifierMixin):
def init(self, base_classifiers, meta_classifier, n_splits=5):
"""
param base_classifiers: list of estimators
param meta_classifier: final_estimator
param n_splits: cv
"""
self.base_classifiers = base_classifiersself
meta_classifier = meta_classifierself
n_splits = n_splits
def fit(self, X, y):
"""
:param X: train data
:param y: train label
"""
n_samples = X.shape[0]
n_classifiers = len(self.base_classifiers)
n_classes = len(np.unique(y)) # Получить количество категорий
base_probabilities = np.zeros((n_samples, n_classifiers * n_classes)) # Используется для хранения прогнозируемых вероятностей базового классификатора
# Настройка кросс-валидации с помощью StratifiedKFold, совместимо с StackingClassifier
kf = StratifiedKFold(n_splits=self.n_splits, shuffle=False, random_state=None)
# сброс индексов данных
X_re_index = X.reset_index(drop=True)
y_re_index = y.reset_index(drop=True)
# Обучить каждый базовый классификатор и сгенерировать прогнозируемые вероятности
for i, clf in enumerate(self.base_classifiers):
fold_probabilities = np.zeros((n_samples, n_classes))
# Обучение и прогнозирование для каждого фолда
for train_index, val_index in kf.split(X_re_index,y_re_index):
X_train, X_val = X_re_index.iloc[train_index], X_re_index.iloc[val_index]
y_train, y_val = y_re_index.iloc[train_index], y_re_index.iloc[val_index]
# Обучение базового классификатора
clf.fit(X_train, y_train)
# Прогнозирование вероятности на валидационном наборе
fold_probabilities[val_index] = clf.predict_proba(X_val)
# Сохранить прогнозируемые вероятности каждого базового классификатора в base_probabilities
base_probabilities[:, i * n_classes: (i + 1) * n_classes] = fold_probabilities
# Обучить мета-классификатор, используя прогнозируемые вероятности базовых классификаторов
self.meta_classifier.fit(base_probabilities, y_re_index)
return self
def predict(self, X):
"""
:param X: test data
"""
# Получить прогнозируемую вероятность каждого базового классификатора
base_probabilities = np.column_stack([clf.predict_proba(X) for clf in self.base_classifiers])
# Использовать мета-классификатор для прогнозирования окончательной метки
return self.meta_classifier.predict(base_probabilities)
def predict_proba(self, X):
"""
:param X: test data
"""
# Получить прогнозируемую вероятность каждого базового классификатора
base_probabilities = np.column_stack([clf.predict_proba(X) for clf in self.base_classifiers])
# Использовать мета-классификатор для получения прогнозируемой вероятности
return self.meta_classifier.predict_proba(base_probabilities)
Ответ или решение
Ручная реализация стекинга в Python: анализ и устранение проблем
Реализация стекинга вручную в Python представляет собой интересную задачу, особенно с учетом существующих библиотек, таких как Scikit-learn. Однако, важное преимущество ручной имплементации в том, что она позволяет глубже понять внутренние процессы работы модели и гибко настраивать параметры под специфические требования.
Почему может возникнуть расхождение в результатах
Несмотря на использование хорошо известных методов и алгоритмов для стекинга, результаты вашей кастомной реализации могут отличаться от sklearn.ensemble.StackingClassifier()
. Это может быть связано с несколькими факторами:
-
Неучтенные параметры и метрики: Встроенный
StackingClassifier
может использовать дополнительные параметры и методы, такие как метрики, которые неявно влияют на обучение модели. Также стоит обратить внимание на другие параметры инициализации, которые могут отличаться. -
Особенности кросс-валидации: Сначала убедитесь, что вы используете одни и те же селекторы данных для кросс-валидации. Складывается впечатление, что у вас настроены разумные параметры для
StratifiedKFold
, но, возможно, стоит также внимательно рассмотреть параметрshuffle
иrandom_state
. -
Обработка данных: Убедитесь, что данные обрабатываются одинаково на стадии обучения и предсказания, включая возможные трансформации или нормализации.
-
Порядок выполнения: Склонно считать, что порядок выполнения операций может оказывать влияние на конечный результат. Попробуйте пересмотреть либо перепроверить порядок выполнения, особенно в случае, если вы инициализировали что-то вне конструкции цикла, что может влиять на пробный набор данных.
Рекомендации для улучшения
-
Сравнительный анализ: Создайте контрольные точки после каждого этапа (например, после обучения базовых классификаторов, после генерации вероятностей) и сравните их с ожидаемыми результатами из
StackingClassifier
. -
Трассировка кода: Используйте инструменты отладки, такие как
pdb
, или инструмент профилирования кода для того, чтобы видеть шаги выполнения программы в реальном времени. -
Дополнительные проверки: Проверьте внутренние состояния отдельных классификаторов и гарантируйте последовательное применение функций предсказания и вероятности.
-
Логирование и отладка: Добавьте логирование для критически важных частей кода, с подробностями о параметрах и размерностях массивов, чтобы облегчить процесс отладки.
Заключение
Если вы уверены, что параметры для всех используемых классификаторов и мета-классификатора установлены правильно, предлагаем вам сфокусироваться на перечисленных выше аспектах. Поскольку стеккинг—достаточно комплексный процесс, каждый его компонент должен быть тщательно настроен. Использование библиотеки Sklearn посредством анализа более подробно может вам существенно помочь.
Кроме того, опыт создания кастомных решений даёт глубокие знания временной сложности и тонкостей работы алгоритмов машинного обучения, что может быть применено в других проектах. Надеюсь, эти советы помогут вам не только устранить текущие расхождения, но и достичь более качественных результатов в будущем.