含ADASYN的imblearn管道模型公平性优化报错求助
解决Fairlearn ExponentiatedGradient与imblearn重采样管道的样本权重不匹配问题
问题重现
我使用包含ADASYN的imblearn管道训练模型:
loaded_model = Pipeline(steps=[('feature_scaler', StandardScaler()), ('adasyn_resampling', ADASYN(random_state=123)), ('low_variance_remover', VarianceThreshold(threshold=0.01)), ('feature_selection', SelectFromModel(estimator=RandomForestClassifier(random_state=0), max_features=35)), ('classifier', CalibratedClassifierCV(base_estimator=LogisticRegression(C=0.1, penalty='l1', random_state=0, solver='saga'), method='isotonic'))])
尝试用Fairlearn的ExponentiatedGradient结合EqualizedOdds约束缓解模型不公平性:
from fairlearn.reductions import EqualizedOdds, ExponentiatedGradient exponentiated_gradient = ExponentiatedGradient( estimator=loaded_model, constraints=EqualizedOdds(difference_bound=0.01), sample_weight_name="classifier__sample_weight") exponentiated_gradient.fit(X_train.drop(columns=['PCa-ID']), y_train, sensitive_features=sf_train)
运行时触发维度不匹配错误:
ValueError: sample_weight.shape == (4834,), expected (6967,)!
错误原因
错误核心是管道内的ADASYN重采样改变了样本数量:ExponentiatedGradient生成的sample_weight基于原始训练集(4834个样本),但ADASYN重采样后生成了更多样本(6967个),导致传递给最终分类器的样本权重维度与重采样后的数据集不匹配,触发校验错误。
解决方案
方案1:将重采样移到Fairlearn流程外(推荐)
先对原始训练集完成ADASYN重采样,再用处理后的数据集训练带公平约束的模型,从根源避免权重维度冲突:
from imblearn.over_sampling import ADASYN from sklearn.pipeline import Pipeline # 执行ADASYN重采样,同步处理敏感特征 adasyn = ADASYN(random_state=123) X_resampled, y_resampled = adasyn.fit_resample(X_train.drop(columns=['PCa-ID']), y_train) sf_resampled = sf_train.loc[adasyn.sample_indices_] # 定义不含重采样步骤的管道 model_pipeline = Pipeline(steps=[ ('feature_scaler', StandardScaler()), ('low_variance_remover', VarianceThreshold(threshold=0.01)), ('feature_selection', SelectFromModel(estimator=RandomForestClassifier(random_state=0), max_features=35)), ('classifier', CalibratedClassifierCV(base_estimator=LogisticRegression(C=0.1, penalty='l1', random_state=0, solver='saga'), method='isotonic')) ]) # 训练公平模型 exponentiated_gradient = ExponentiatedGradient( estimator=model_pipeline, constraints=EqualizedOdds(difference_bound=0.01), sample_weight_name="classifier__sample_weight") exponentiated_gradient.fit(X_resampled, y_resampled, sensitive_features=sf_resampled)
方案2:自定义支持权重映射的重采样器
若必须在管道内保留ADASYN,可自定义采样器,将原始样本权重映射到重采样后的样本(少数类的副本继承原始样本的权重):
from imblearn.base import BaseSampler class WeightedADASYN(BaseSampler): def __init__(self, random_state=123): self.adasyn = ADASYN(random_state=random_state) self.sample_indices_ = None def fit_resample(self, X, y, sample_weight=None): X_resampled, y_resampled = self.adasyn.fit_resample(X, y) self.sample_indices_ = self.adasyn.sample_indices_ # 将原始样本权重映射到重采样后的样本集合 if sample_weight is not None: resampled_weights = sample_weight[self.sample_indices_] return X_resampled, y_resampled, resampled_weights return X_resampled, y_resampled # 重新定义管道,使用自定义采样器 loaded_model = Pipeline(steps=[ ('feature_scaler', StandardScaler()), ('adasyn_resampling', WeightedADASYN(random_state=123)), ('low_variance_remover', VarianceThreshold(threshold=0.01)), ('feature_selection', SelectFromModel(estimator=RandomForestClassifier(random_state=0), max_features=35)), ('classifier', CalibratedClassifierCV(base_estimator=LogisticRegression(C=0.1, penalty='l1', random_state=0, solver='saga'), method='isotonic')) ]) # 训练时传递顶层sample_weight,由自定义采样器处理映射 exponentiated_gradient = ExponentiatedGradient( estimator=loaded_model, constraints=EqualizedOdds(difference_bound=0.01), sample_weight_name="sample_weight") exponentiated_gradient.fit(X_train.drop(columns=['PCa-ID']), y_train, sensitive_features=sf_train)
内容的提问来源于stack exchange,提问作者Ana Rodrigues
相关产品推荐
相关产品推荐

