Этот код по существу повторяет функциональность sklearn.ensemble.StackingClassifier() вручную. Однако, протестировав его на наборе данных Wine и сравнив результаты двух методов, я обнаружил расхождения. Несмотря на то, что я потратил на это много времени, я не смог точно определить проблему. Буду очень признателен за любую помощь или идеи сообщества. Большое спасибо! Код следующий:
Код: Выделить всё
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)) # Get the number of categories
base_probabilities_1 = np.zeros((n_samples, n_classifiers * n_classes)) # Used to store the predicted probabilities of the base classifier
# Setting up cross validation by StratifiedKFold, consistent with StackingClassifier
kf = StratifiedKFold(n_splits=self.n_splits, shuffle=False, random_state=None)
# reset index of data
X_re_index = X.reset_index(drop=True)
y_re_index = y.reset_index(drop=True)
# Train each base classifier and generate prediction probabilities
for i, clf in enumerate(self.base_classifiers):
fold_probabilities = np.zeros((n_samples, n_classes))
# Train and predict for each fold
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]
# Train base classifier
clf.fit(X_train, y_train)
# Predict probabilities on validation set
fold_probabilities[val_index] = clf.predict_proba(X_val)
# Save the predicted probabilities of each base classifier into base_probabilities
base_probabilities_1[:, i * n_classes: (i + 1) * n_classes] = fold_probabilities
# Train the meta-classifier using the predicted probabilities of the base classifiers
self.meta_classifier.fit(base_probabilities_1, y_re_index)
return self
def predict(self, X):
"""
:param X: test data
"""
# Get the predicted probability of each base classifier
base_probabilities = np.column_stack([clf.predict_proba(X) for clf in self.base_classifiers])
# Use the meta-classifier to predict the final label
return self.meta_classifier.predict(base_probabilities)
def predict_proba(self, X):
"""
:param X: test data
"""
# Get the predicted probability of each base classifier
base_probabilities = np.column_stack([clf.predict_proba(X) for clf in self.base_classifiers])
# Use the meta-classifier to get the predict probability
return self.meta_classifier.predict_proba(base_probabilities)
Важно отметить, что гиперпараметры и random_state как для базовых классификаторов, так и для метаклассификатора были исправлены, поэтому эти факторы можно исключить как причину.
Подробнее здесь: https://stackoverflow.com/questions/793 ... ntation-of