使用fairlearn的ExponentiatedGradient后,GridSearchCV无cv_results_属性
问题原因
Fairlearn的ExponentiatedGradient在拟合时,并不会直接用你传入的那个GridSearchCV实例去训练——它会每次克隆一个新的GridSearchCV副本,在迭代中训练这些副本。你通过mitigator.estimator拿到的是最开始创建的、根本没被训练过的GridSearchCV对象,自然没有cv_results_属性。
解决方案
1. 直接取内部训练过的克隆模型
ExponentiatedGradient会把所有迭代里训练好的模型存在_predictors这个私有属性里,这些克隆出来的GridSearchCV都是训练过的,自带cv_results_:
# 挨个查看每个迭代模型的交叉验证结果 for i, model in enumerate(mitigator._predictors): print(f"第{i+1}轮训练的模型cv结果:") print(model.cv_results_)
⚠️ 注意:_predictors是私有属性,后续Fairlearn版本可能会调整,使用时留意版本兼容性。
2. 先跑GridSearch再传最优模型
如果不需要在公平性约束下做超参数搜索,可以先单独把GridSearchCV跑一遍,拿到最优模型后再传给ExponentiatedGradient:
# 先完成超参数搜索 gs.fit(train_X, y_train, sensitive_features=x_train[set_sa]) # 提取最优模型 best_model = gs.best_estimator_ # 用最优模型初始化公平性调整器 mitigator = ExponentiatedGradient(best_model, constraints=EqualizedOdds()) mitigator.fit(train_X, y_train, sensitive_features=x_train[set_sa]) # 直接访问原GridSearchCV的cv_results_ print(gs.cv_results_)
这种方法的局限是:超参数搜索未考虑公平性约束,最终模型的公平性表现可能不如在约束下搜索的结果。
3. 自定义GridSearchCV包装类保存结果
写个简单的包装类继承GridSearchCV,训练后自动把cv_results_存到实例属性里,再让ExponentiatedGradient用这个包装类:
from sklearn.model_selection import GridSearchCV class GridSearchWithResults(GridSearchCV): def fit(self, X, y=None, **fit_params): super().fit(X, y, **fit_params) # 把cv结果存到自定义属性里 self.trained_cv_results = self.cv_results_ # 创建自定义类的实例 gs = GridSearchWithResults( estimator=model, param_grid=param, cv=RepeatedKFold(n_splits=5, n_repeats=2), scoring=scoring, return_train_score=True, refit='roc_auc_curve', n_jobs=-1) mitigator = ExponentiatedGradient(gs, constraints=EqualizedOdds()) mitigator.fit(train_X, y_train, sensitive_features=x_train[set_sa]) # 遍历内部模型取结果 for model in mitigator._predictors: print(model.trained_cv_results)
内容的提问来源于stack exchange,提问作者Tania Carvalho
相关产品推荐
相关产品推荐

