使用StackingCVClassifier堆叠Sklearn与Keras分类器遇维度错误求助
问题解决:StackingCVClassifier维度不匹配错误
错误原因
你遇到的ValueError是因为KerasClassifier的预测输出维度与sklearn原生分类器(Logistic Regression、Random Forest)不一致导致的:
- sklearn二分类器的
predict_proba方法会返回形状为(n_samples, 2)的数组,包含负类和正类的概率; - 你的Keras模型使用
sigmoid输出,predict_proba仅返回正类概率,形状为(n_samples, 1)(部分版本下可能意外产生3维数组); - StackingCVClassifier在拼接这些元特征时,维度不匹配就会触发错误。
解决方法
方法1:统一KerasClassifier的输出维度
自定义一个包装类,修改KerasClassifier的predict_proba方法,让它输出和sklearn一致的(n_samples, 2)格式:
from keras.wrappers.scikit_learn import KerasClassifier import numpy as np class KerasClassifierWrapper(KerasClassifier): def predict_proba(self, X, **kwargs): # 获取Keras模型的正类概率 proba_pos = super().predict_proba(X, **kwargs) # 补全负类概率,生成(n_samples, 2)的数组 proba_neg = 1 - proba_pos return np.hstack([proba_neg, proba_pos]) # 替换原来的NN_clf定义 NN_clf = KerasClassifierWrapper(build_fn=create_model, epochs=5, batch_size=5) NN_clf._estimator_type = "classifier"
方法2:使用类别标签作为元特征
如果不需要用概率作为元特征,可以设置StackingCVClassifier的use_probas=False,此时所有基分类器会输出预测类别(一维数组),拼接时维度一致:
clf = StackingCVClassifier( classifiers=[pipeline1, pipeline2, pipeline3], meta_classifier=MLPClassifier(), use_probas=False )
额外优化建议
- 移除多余的Flatten层:你的Keras模型输入已经是二维的(样本数×特征数),
Flatten()层在这里没有作用,可以删除; - 适配新版本Keras:新版本Keras中
build_fn参数已被废弃,建议改用model参数,同时优化学习率参数名:
def create_model(): model = Sequential() model.add(Dense(10, input_dim=10, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(units=1, activation='sigmoid')) # 新版本Keras中lr改为learning_rate optimizer = keras.optimizers.RMSprop(learning_rate=0.001) model.compile( loss='binary_crossentropy', optimizer=optimizer, metrics=[keras.metrics.AUC(), 'accuracy'] ) return model # 新版本KerasClassifier用法 NN_clf = KerasClassifierWrapper(model=create_model(), epochs=5, batch_size=5)
修改后的完整代码
from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from tensorflow import keras from keras.models import Sequential from keras.layers import Dense, Dropout from mlxtend.classifier import StackingCVClassifier from mlxtend.feature_selection import ColumnSelector from sklearn.pipeline import make_pipeline import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from keras.wrappers.scikit_learn import KerasClassifier from sklearn.neural_network import MLPClassifier X, y = make_classification() X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=0) # 定义神经网络模型(移除多余Flatten层) def create_model(): model = Sequential() model.add(Dense(10, input_dim=10, activation='relu')) model.add(Dropout(0.2)) optimizer = keras.optimizers.RMSprop(learning_rate=0.001) model.add(Dense(units=1, activation='sigmoid')) model.compile( loss='binary_crossentropy', optimizer=optimizer, metrics=[keras.metrics.AUC(), 'accuracy'] ) return model # 包装KerasClassifier统一输出维度 class KerasClassifierWrapper(KerasClassifier): def predict_proba(self, X, **kwargs): proba_pos = super().predict_proba(X, **kwargs) proba_neg = 1 - proba_pos return np.hstack([proba_neg, proba_pos]) NN_clf = KerasClassifierWrapper(model=create_model(), epochs=5, batch_size=5) NN_clf._estimator_type = "classifier" # 定义各特征子集的管道 pipeline1 = make_pipeline(ColumnSelector(cols=np.arange(0, 5)), LogisticRegression()) pipeline2 = make_pipeline(ColumnSelector(cols=np.arange(5, 10)), RandomForestClassifier()) pipeline3 = make_pipeline(ColumnSelector(cols=np.arange(10, 20)), NN_clf) # 堆叠模型 clf = StackingCVClassifier(classifiers=[pipeline1, pipeline2, pipeline3], meta_classifier=MLPClassifier()) clf.fit(X_train, y_train) print("Stacking model score: %.3f" % clf.score(X_val, y_val))
内容的提问来源于stack exchange,提问作者zyleen
相关产品推荐
相关产品推荐

