OptunaSearchCV能否对完整机器学习Pipeline进行超参数调优?
问题与解答
问题描述
我用GridSearchCV对包含预处理、不平衡处理、特征选择及CatBoostClassifier模型的完整ImbPipeline进行超参数调优,但过程耗时极长。想改用OptunaSearchCV提速,但不确定OptunaSearchCV是否只能调优模型本身的超参数,不知道该用何种Distribution设置SelectKBest(f_classif, k=40)、RobustScaler()这类组件的参数。原代码如下:
preprocessor = ColumnTransformer( [ ('OneHotEncoder', OneHotEncoder(drop='if_binary', sparse_output=False), binary_cols), ('CatBoostEncoder', CatBoostEncoder(random_state=RANDOM_STATE), non_binary_cat_cols), ('StandardScaler', StandardScaler(), num_cols) ], verbose_feature_names_out=False, remainder='drop' ) pipe_final = ImbPipeline([ ('preprocessor', preprocessor), ('target_imbalance', ADASYN()), ('selection', PCA()), ('models', CatBoostClassifier(random_state=RANDOM_STATE)) ]) # 用于CatBoostClassifier的超参数 param_grid = { 'models__iterations': [1000, 2000, 3000], 'models__class_weights': ['Balanced', None], 'target_imbalance': [ADASYN(random_state=RANDOM_STATE), SMOTETomek(random_state=RANDOM_STATE), SMOTE(random_state=RANDOM_STATE, k_neighbors=10), 'passthrough'], 'preprocessor__StandardScaler': [StandardScaler(), RobustScaler(), MinMaxScaler(), PowerTransformer(), QuantileTransformer(), Normalizer(),PolynomialFeatures(degree=2, include_bias=False), 'passthrough'], 'selection': [PCA(random_state=RANDOM_STATE, n_components="mle", svd_solver="full"), SelectKBest(mutual_info_classif, k=40), SelectKBest(f_classif, k=40), SelectKBest(chi2, k=40), SelectPercentile(mutual_info_classif, percentile=10), SelectPercentile(f_classif, percentile=10), SelectFromModel(CatBoostClassifier(random_state=RANDOM_STATE)), SelectFromModel(LogisticRegression(random_state=RANDOM_STATE)), SelectFromModel(RandomForestClassifier(random_state=RANDOM_STATE)), 'passthrough'], } gs = GridSearchCV( pipe_final, param_grid, cv=5, scoring='roc_auc', n_jobs=-1 ) # 启动超参数搜索 gs.fit(X, y_enc)
解答
你的理解有误,OptunaSearchCV完全支持对整个Pipeline的所有组件进行超参数调优,包括预处理、不平衡处理、特征选择环节,并非只能调优模型本身。以下是具体实现思路和代码示例:
核心思路
- 枚举组件类型:对于需要选择不同组件(比如不同的Scaler、采样器、特征选择器)的场景,使用Optuna的
CategoricalDistribution定义候选选项,逻辑和GridSearchCV的列表枚举一致,但Optuna会智能筛选而非穷举。 - 调优组件参数:对于组件的可调参数(比如SelectKBest的
k值、SelectPercentile的percentile值),用对应的数值分布(如IntDistribution)让Optuna在合理范围内搜索最优值,比固定值更灵活。 - 贝叶斯优化提速:Optuna采用贝叶斯优化算法,会根据之前试验的结果动态调整后续搜索方向,避免网格搜索的全量穷举,大幅减少无效试验,从而缩短调优时间。
修改后的代码示例
from optuna.integration import OptunaSearchCV from optuna.distributions import CategoricalDistribution, IntDistribution # 保留原Pipeline定义 preprocessor = ColumnTransformer( [ ('OneHotEncoder', OneHotEncoder(drop='if_binary', sparse_output=False), binary_cols), ('CatBoostEncoder', CatBoostEncoder(random_state=RANDOM_STATE), non_binary_cat_cols), ('StandardScaler', StandardScaler(), num_cols) ], verbose_feature_names_out=False, remainder='drop' ) pipe_final = ImbPipeline([ ('preprocessor', preprocessor), ('target_imbalance', ADASYN()), ('selection', PCA()), ('models', CatBoostClassifier(random_state=RANDOM_STATE)) ]) # 定义Optuna搜索空间 param_distributions = { # 模型参数调优 'models__iterations': IntDistribution(low=1000, high=3000, step=1000), 'models__class_weights': CategoricalDistribution(['Balanced', None]), # 不平衡处理组件选择 'target_imbalance': CategoricalDistribution([ ADASYN(random_state=RANDOM_STATE), SMOTETomek(random_state=RANDOM_STATE), SMOTE(random_state=RANDOM_STATE, k_neighbors=10), 'passthrough' ]), # 预处理Scaler选择 'preprocessor__StandardScaler': CategoricalDistribution([ StandardScaler(), RobustScaler(), MinMaxScaler(), PowerTransformer(), QuantileTransformer(), Normalizer(), PolynomialFeatures(degree=2, include_bias=False), 'passthrough' ]), # 特征选择组件及参数调优(扩展参数灵活性) 'selection': CategoricalDistribution([ PCA(random_state=RANDOM_STATE, n_components="mle", svd_solver="full"), # 让SelectKBest的k值成为可调参数(示例:20-80之间选) lambda trial: SelectKBest(mutual_info_classif, k=trial.suggest_int('selection__k', 20, 80)), lambda trial: SelectKBest(f_classif, k=trial.suggest_int('selection__k', 20, 80)), lambda trial: SelectKBest(chi2, k=trial.suggest_int('selection__k', 20, 80)), lambda trial: SelectPercentile(mutual_info_classif, percentile=trial.suggest_int('selection__percentile', 5, 20)), lambda trial: SelectPercentile(f_classif, percentile=trial.suggest_int('selection__percentile', 5, 20)), SelectFromModel(CatBoostClassifier(random_state=RANDOM_STATE)), SelectFromModel(LogisticRegression(random_state=RANDOM_STATE)), SelectFromModel(RandomForestClassifier(random_state=RANDOM_STATE)), 'passthrough' ]), } # 初始化OptunaSearchCV oscv = OptunaSearchCV( pipe_final, param_distributions, cv=5, scoring='roc_auc', n_jobs=-1, n_trials=100, # 设定总试验次数,远小于网格搜索的组合数 random_state=RANDOM_STATE, verbose=1 ) # 启动超参数搜索 oscv.fit(X, y_enc) # 查看最优参数和得分 print("最优参数:", oscv.best_params_) print("最优ROC-AUC得分:", oscv.best_score_)
关键说明
- 对于需要动态调整参数的组件(如SelectKBest的
k),可以用lambda函数结合trial.suggest_*方法实现,让Optuna在指定范围内搜索最优值。 n_trials参数控制总试验次数,可根据时间预算调整,通常100-200次试验就能找到接近最优的结果,远少于网格搜索的全量组合(你的原网格组合数是324810=1920次,Optuna只需1/20的试验次数就能达到相近效果)。- 所有Pipeline组件的参数都可以通过
组件名__参数名的方式定义搜索空间,和GridSearchCV的参数命名规则完全一致。
内容的提问来源于stack exchange,提问作者Павел Катровцев
相关产品推荐
相关产品推荐

