如何将Keras模型集成至序列后向特征选择代码并解决报错
集成方案可行性结论
该集成方案完全可行,你遇到的报错不涉及Scikeras封装、手写序列后向选择(SBS)、Keras分类器本身的逻辑冲突,仅需做少量适配即可正常运行,最终输出目标Top5特征。
报错根因
触发ValueError: Input 0 of layer "sequential_410" is incompatible with the layer: expected shape=(None, 45), found shape=(None, 44)的直接原因:
- 你初始化Keras二分类网络时,将
input_shape硬编码为初始全量特征的维度45 - SBS的核心逻辑是逐轮迭代删除1个对性能贡献最低的特征,每一轮迭代使用的输入特征维度会逐次减1:第一轮训练用全量45维特征,第二轮就变为44维,第三轮43维,直到维度降到你指定的保留特征数5为止
- 此前手动修改
input_shape参数无效,是因为你仅修改了模型初始化阶段的固定维度值,没有让模型适配SBS逐轮变化的输入维度,特征删到44维时,写死45维输入的模型自然会报维度不匹配错误。
代码修改方案
所有修改不改变你原有三部分代码的技术栈、调用逻辑,仅需补充两个适配点即可:
1. 改造Scikeras封装的Keras模型构建逻辑
不要在模型构建函数中硬编码输入维度,将输入维度设置为动态传入参数,让Scikeras在每轮调用fit时,自动根据当前传入的特征子集维度生成匹配输入层的模型:
from scikeras.wrappers import KerasClassifier from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout # 动态维度模型构建函数,不要写死input_shape数值 def build_dnn(n_features): model = Sequential() # 输入维度随传入的特征数自动适配 model.add(Dense(32, activation='relu', input_shape=(n_features,))) model.add(Dropout(0.2)) model.add(Dense(16, activation='relu')) model.add(Dense(1, activation='sigmoid')) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model # 初始化符合sklearn接口的分类器,开启输入维度自动推断 clf = KerasClassifier( model=build_dnn, epochs=30, batch_size=16, verbose=0, random_state=42, # 固定随机种子保证结果可复现 model__n_features=-1 # 占位参数,触发Scikeras自动从输入数据推断特征维度 )
2. 校验手写SBS类的特征索引逻辑
确认你从零实现的SequentialBackwardSearch类满足两个逻辑要求即可,不需要重构原有类结构:
- 每轮迭代删除特征后,同步更新当前轮次保留的特征索引列表,不要残留上一轮的高维索引
- 每轮执行模型
fit、score操作前,必须用当前轮次的特征索引从原始数据集切出对应列的特征子集,再传入模型,不要直接传入全量特征
3. 运行获取结果
完成上述修改后,直接按你原有的测试逻辑,将封装好的clf传入SequentialBackwardSearch类,指定保留特征数为5启动训练即可。训练完成后,通过SBS类实例的最优特征属性(通常为best_features_或你自定义的对应属性)拿到Top5特征的列索引,映射回原始特征名即为最终筛选结果。
补充:如果后续切换为scikit-learn内置的序列特征选择模块报同类维度错误,上述动态模型构建的修改方式完全通用。
内容的提问来源于stack exchange,提问作者tay123
相关产品推荐
相关产品推荐

