AI公平性:偏见检测与消除的完全指南 引言 AI系统的不公平性问题日益受到关注,从招聘、信贷到司法,AI偏见可能导致歧视性决策。本文将深入探讨AI偏见的来源、检测方法和消除技术,提供完整的公平AI实践指南。 一、AI偏见的来源与类型 1.1 偏见的来源 数据层面: 历史偏见:训练数据反映历史歧视 代表性不足:少数群体数据不足 标签偏见:人工标注的主观性 选择偏见:数据收集方法有偏 算法层面: 目标函数偏向:优化目标忽视公平性 特征选择:使用代理变量(如邮编→种族) 模型假设:统计歧视(利用群体差异) 部署层面: 反馈循环:AI决策影响未来数据 上下漂移:模型在不同环境中表现不同 交互偏见:用户行为影响模型输出 1.
AI系统的不公平性问题日益受到关注,从招聘、信贷到司法,AI偏见可能导致歧视性决策。本文将深入探讨AI偏见的来源、检测方法和消除技术,提供完整的公平AI实践指南。
数据层面:
算法层面:
部署层面:
| 偏见类型 | 说明 | 示例 |
|---|---|---|
| 分配偏见 | 不同群体获得不同结果 | 男性获得更多贷款批准 |
| 质量偏见 | 服务质量不同 | 少数族裔识别准确率低 |
| 再现偏见 | 放大社会刻板印象 | 招聘AI偏好男性 |
| 链接偏见 | 基于关联的歧视 | 算法推荐高薪工作给男性 |
定义:
不同群体获得正结果的概率相等。
数学公式:
P(Ŷ=1|A=0) = P(Ŷ=1|A=1) 其中: - Ŷ: 预测结果 - A: 受保护属性(如性别、种族)
实现代码:
import numpy as np def demographic_parity(y_pred, protected_attribute): """计算统计均等""" # 计算各群体的正结果率 group_0_rate = np.mean(y_pred[protected_attribute == 0]) group_1_rate = np.mean(y_pred[protected_attribute == 1]) # 计算差异 difference = abs(group_0_rate - group_1_rate) return { 'group_0_rate': group_0_rate, 'group_1_rate': group_1_rate, 'difference': difference, 'satisfied': difference < 0.05 # 阈值5% } # 使用 y_pred = model.predict(X_test) protected = X_test['gender'] # 0: 男性, 1: 女性 parity = demographic_parity(y_pred, protected) print(parity)
定义:
在真实标签相同的条件下,不同群体的预测率相等。
数学公式:
P(Ŷ=1|A=0, Y=1) = P(Ŷ=1|A=1, Y=1) P(Ŷ=0|A=0, Y=0) = P(Ŷ=0|A=1, Y=0)
实现代码:
def equalized_odds(y_pred, y_true, protected_attribute): """计算机会均等""" results = {} for y_val in [0, 1]: # 真实标签 for group in [0, 1]: # 受保护群体 mask = (y_true == y_val) & (protected_attribute == group) if mask.sum() > 0: rate = np.mean(y_pred[mask]) results[f'y={y_val}_group={group}'] = rate # 检查是否满足 tpr_diff = abs(results['y=1_group=0'] - results['y=1_group=1']) fpr_diff = abs(results['y=0_group=0'] - results['y=0_group=1']) results['satisfied'] = (tpr_diff < 0.05) and (fpr_diff < 0.05) return results
定义:
对于相同预测分数,不同群体的真实概率应该相等。
实现代码:
from sklearn.calibration import calibration_curve def calibration_fairness(y_true, y_pred_proba, protected_attribute): """计算校准公平性""" results = {} for group in [0, 1]: mask = protected_attribute == group if mask.sum() > 0: prob_true, prob_pred = calibration_curve( y_true[mask], y_pred_proba[mask], n_bins=10 ) results[f'group_{group}_calibration'] = { 'prob_true': prob_true, 'prob_pred': prob_pred } return results
定义:
衡量收入/结果不平等的指标(0表示完全平等)。
def theil_index(y_true, y_pred, protected_attribute): """计算Theil指数""" N = len(y_true) total = np.sum(y_pred) if total == 0: return 0 theil = 0 for i in range(N): p_i = y_pred[i] / total theil += p_i * np.log(p_i * N) return theil / N
安装:
pip install fairlearn
使用示例:
from fairlearn.metrics import MetricFrame from fairlearn.reductions import ExponentiatedGradient from fairlearn.constraints import DemographicParity # 准备数据 y_true = y_test y_pred = model.predict(X_test) protected_attribute = X_test['gender'] # 计算公平性指标 metrics = { 'accuracy': accuracy_score, 'selection_rate': selection_rate, # 选择率 'false_positive_rate': false_positive_rate, 'true_positive_rate': true_positive_rate } metric_frame = MetricFrame( metrics=metrics, y_true=y_true, y_pred=y_pred, sensitive_features=protected_attribute ) # 打印按群体分解的指标 print(metric_frame.by_group) # 检查是否满足统计均等 dp = DemographicParity() print(dp.gamma(y_pred, protected_attribute))
消除偏见(后处理):
from fairlearn.postprocessing import ThresholdOptimizer # 训练阈值优化器 to = ThresholdOptimizer( constraints="demographic_parity", objective="accuracy_score", prefit=True ) # 拟合优化器 to.fit(X_train, y_train, sensitive_features=protected_train) # 应用公平性优化 y_pred_fair = to.predict(X_test, sensitive_features=protected_test)
安装:
pip install aif360
使用示例:
from aif360.datasets import GermanDataset from aif360.metrics import BinaryLabelDatasetMetric from aif360.algorithms.preprocessing import Reweighing # 加载数据集 dataset = GermanDataset( protected_attribute_names=['sex'], # 性别 privileged_classes=[['male']], # 特权群体 features_to_drop=['personal_status', 'sex'] ) # 计算公平性指标 metric = BinaryLabelDatasetMetric( dataset, unprivileged_groups=[{'sex': 0}], privileged_groups=[{'sex': 1}] ) # 差异影响 disparate_impact = metric.disparate_impact() print(f"差异影响: {disparate_impact}") # 均值差异 mean_diff = metric.mean_difference() print(f"均值差异: {mean_diff}")
消除偏见(预处理):
# 重加权 rw = Reweighing( unprivileged_groups=[{'sex': 0}], privileged_groups=[{'sex': 1}] ) dataset_transformed = rw.fit_transform(dataset) # 训练模型 model = LogisticRegression() model.fit( dataset_transformed.features, dataset_transformed.labels, sample_weight=dataset_transformed.instance_weights )
使用示例:
from aif360.algorithms.postprocessing import EqOddsPostprocessing # 机会均等后处理 pp = EqOddsPostprocessing( unprivileged_groups=[{'sex': 0}], privileged_groups=[{'sex': 1}] ) # 拟合后处理器 pp.fit(dataset, dataset.labels) # 应用公平性优化 y_pred_fair = pp.predict(y_pred, protected_attribute)
过采样少数群体:
from imblearn.over_sampling import SMOTE from collections import Counter def fair_oversample(X, y, protected_attr): """公平过采样""" # 为每个群体分别过采样 X_resampled = [] y_resampled = [] for group in np.unique(protected_attr): group_mask = protected_attr == group # 提取该群体数据 X_group = X[group_mask] y_group = y[group_mask] # SMOTE过采样 smote = SMOTE(k_neighbors=5) X_res, y_res = smote.fit_resample(X_group, y_group) X_resampled.append(X_res) y_resampled.append(y_res) # 合并所有群体 return np.vstack(X_resampled), np.hstack(y_resampled) # 使用 X_fair, y_fair = fair_oversample(X_train, y_train, train_gender) print(f"原始分布: {Counter(y_train)}") print(f"重采样后: {Counter(y_fair)}")
欠采样多数群体:
from imblearn.under_sampling import RandomUnderSampler def fair_undersample(X, y, protected_attr): """公平欠采样""" rus = RandomUnderSampler(sampling_strategy='auto') X_resampled = [] y_resampled = [] for group in np.unique(protected_attr): group_mask = protected_attr == group X_group = X[group_mask] y_group = y[group_mask] X_res, y_res = rus.fit_resample(X_group, y_group) X_resampled.append(X_res) y_resampled.append(y_res) return np.vstack(X_resampled), np.hstack(y_resampled)
为少数群体分配更高权重:
def compute_fair_weights(y, protected_attr): """计算公平权重""" weights = np.ones(len(y)) for group in np.unique(protected_attr): group_mask = protected_attr == group group_size = group_mask.sum() # 权重与群体大小成反比 weight = len(y) / (len(np.unique(protected_attr)) * group_size) weights[group_mask] = weight return weights # 使用 sample_weights = compute_fair_weights(y_train, train_gender) model.fit(X_train, y_train, sample_weight=sample_weights)
合成数据生成:
from aif360.algorithms.preprocessing import Reweighing # 使用重加权生成公平数据 rw = Reweighing( unprivileged_groups=[{'sex': 0}], privileged_groups=[{'sex': 1}] ) # 拟合重加权器 rw.fit(dataset) # 转换数据(修改样本权重) dataset_transformed = rw.transform(dataset) # 训练时使用样本权重 model.fit( dataset_transformed.features, dataset_transformed.labels, sample_weight=dataset_transformed.instance_weights )
添加公平性约束到训练:
from fairlearn.reductions import ExponentiatedGradient, DemographicParity # 定义公平约束 constraint = DemographicParity() # 使用指数梯度下降 mitigator = ExponentiatedGradient( LogisticRegression(), constraints=constraint, eps=0.01 # 允许的公平性差距 ) # 拟合公平模型 mitigator.fit(X_train, y_train, sensitive_features=train_gender) # 预测 y_pred_fair = mitigator.predict(X_test)
使用对抗网络学习公平表示:
import torch import torch.nn as nn class FairModel(nn.Module): def __init__(self, input_dim, hidden_dim): super().__init__() self.encoder = nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim) ) self.predictor = nn.Linear(hidden_dim, 1) self.adversary = nn.Linear(hidden_dim, 1) def forward(self, x): features = self.encoder(x) pred = torch.sigmoid(self.predictor(features)) adv_pred = torch.sigmoid(self.adversary(features)) return pred, adv_pred # 训练 def train_fair_model(model, X, y, protected_attr): optimizer = torch.optim.Adam(model.parameters()) for epoch in range(100): optimizer.zero_grad() # 前向传播 pred, adv_pred = model(X) # 主任务损失(预测) task_loss = nn.BCELoss()(pred, y) # 对抗损失(去除敏感信息) adv_loss = nn.BCELoss()(adv_pred, protected_attr.float()) # 总损失 loss = task_loss - 0.1 * adv_loss # 负号表示对抗 loss.backward() optimizer.step() return model
from fairlearn.reductions import GridSearch from fairlearn.constraints import EqualizedOdds # 网格搜索最佳公平模型 sweep = GridSearch( LogisticRegression(), constraints=EqualizedOdds(), grid_size=50 ) sweep.fit(X_train, y_train, sensitive_features=train_gender) # 获取最佳模型 best_model = sweep.predictor_
问题:
AI招聘系统偏向男性候选人。
检测:
# 加载招聘数据 import pandas as pd df = pd.read_csv('hiring_data.csv') X = df[['skills', 'experience', 'education']] y = df['hired'] protected = df['gender'] # 0: 男, 1: 女 # 训练模型 model = LogisticRegression() model.fit(X, y) y_pred = model.predict(X) # 检测偏见 from fairlearn.metrics import MetricFrame metrics = MetricFrame( metrics={'selection_rate': selection_rate}, y_true=y, y_pred=y_pred, sensitive_features=protected ) print(metrics.by_group) # group_0 (男性): 0.45 # group_1 (女性): 0.28 ← 存在偏见
消除偏见:
from fairlearn.reductions import ExponentiatedGradient # 公平性优化 mitigator = ExponentiatedGradient( LogisticRegression(), constraints=DemographicParity(), eps=0.05 # 允许5%的差距 ) mitigator.fit(X, y, sensitive_features=protected) # 使用公平模型 y_pred_fair = mitigator.predict(X) # 验证 metrics_fair = MetricFrame( metrics={'selection_rate': selection_rate}, y_true=y, y_pred=y_pred_fair, sensitive_features=protected ) print(metrics_fair.by_group) # group_0: 0.38 # group_1: 0.36 ← 偏见显著降低
检测偏见:
from aif360.datasets import GermanCreditDataset from aif360.metrics import BinaryLabelDatasetMetric # 加载数据 dataset = GermanDataset( protected_attribute_names=['age'], privileged_classes=[['age>=25']] ) # 训练模型 from sklearn.linear_model import LogisticRegression model = LogisticRegression() model.fit(dataset.features, dataset.labels) y_pred = model.predict(dataset.features) # 计算公平性指标 metric = BinaryLabelDatasetMetric( dataset, unprivileged_groups=[{'age': 0}], privileged_groups=[{'age': 1}] ) disparate_impact = metric.disparate_impact() print(f"差异影响: {disparate_impact:.3f}") # 输出: 0.65 (<0.8 表示存在偏见)
消除偏见:
from aif360.algorithms.preprocessing import Reweighing # 重加权 rw = Reweighing( unprivileged_groups=[{'age': 0}], privileged_groups=[{'age': 1}] ) dataset_transformed = rw.fit_transform(dataset) # 训练公平模型 model_fair = LogisticRegression() model_fair.fit( dataset_transformed.features, dataset_transformed.labels, sample_weight=dataset_transformed.instance_weights ) # 验证 y_pred_fair = model_fair.predict(dataset.features) metric_fair = BinaryLabelDatasetMetric( dataset.copy(deep=True), unprivileged_groups=[{'age': 0}], privileged_groups=[{'age': 1}] ) metric_fair.labels = y_pred_fair disparate_impact_fair = metric_fair.disparate_impact() print(f"公平化后的差异影响: {disparate_impact_fair:.3f}") # 输出: 0.92 (>0.8, 满足公平性要求)
COMPAS案例研究:
# 模拟COMPAS数据 import numpy as np import pandas as pd # 生成模拟数据 n = 1000 X = np.random.randn(n, 5) # 特征 y = np.random.randint(0, 2, n) # 再犯(0/1) protected = np.random.randint(0, 2, n) # 种族(0: 非洲裔, 1: 欧洲裔) # 训练模型 from sklearn.ensemble import RandomForestClassifier model = RandomForestClassifier() model.fit(X, y) y_pred = model.predict(X) # 计算假阳性率 def false_positive_rate(y_true, y_pred): tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel() return fp / (fp + tn) fpr_black = false_positive_rate(y[protected==0], y_pred[protected==0]) fpr_white = false_positive_rate(y[protected==1], y_pred[protected==1]) print(f"FPR (非洲裔): {fpr_black:.3f}") print(f"FPR (欧洲裔): {fpr_white:.3f}") print(f"比率: {fpr_black/fpr_white:.2f}") # 输出: # FPR (非洲裔): 0.32 # FPR (欧洲裔): 0.18 # 比率: 1.78 → 存在显著偏见 # 应用公平性优化 from fairlearn.postprocessing import ThresholdOptimizer to = ThresholdOptimizer( constraints="equalized_odds", objective="true_positive_rate", prefit=True ) to.fit(X, y, sensitive_features=protected) y_pred_fair = to.predict(X, sensitive_features=protected) # 验证 fpr_black_fair = false_positive_rate(y[protected==0], y_pred_fair[protected==0]) fpr_white_fair = false_positive_rate(y[protected==1], y_pred_fair[protected==1]) print(f"\n公平化后:") print(f"FPR (非洲裔): {fpr_black_fair:.3f}") print(f"FPR (欧洲裔): {fpr_white_fair:.3f}") print(f"比率: {fpr_black_fair/fpr_white_fair:.2f}") # 输出: # FPR (非洲裔): 0.22 # FPR (欧洲裔): 0.20 # 比率: 1.10 → 偏见大幅降低
from prometheus_client import Counter, Histogram # 定义指标 demographic_parity_gauge = Histogram( 'demographic_parity', 'Demographic parity difference', buckets=[0.0, 0.05, 0.1, 0.15, 0.2, 0.3, 0.5, 1.0] ) group_selection_rate = Counter( 'selection_rate', 'Selection rate by group', ['group'] ) def monitor_fairness(y_pred, protected_attr): """监控公平性""" # 计算统计均等 parity = demographic_parity(y_pred, protected_attr) # 记录指标 demographic_parity_gauge.observe(parity['difference']) # 记录各群体选择率 for group in np.unique(protected_attr): group_mask = protected_attr == group rate = np.mean(y_pred[group_mask]) group_selection_rate.labels(group).inc(rate) return parity
def fairness_audit(model, X, y, protected_attr): """公平性审计""" audit_results = {} # 1. 统计均等 y_pred = model.predict(X) dp = demographic_parity(y_pred, protected_attr) audit_results['demographic_parity'] = dp # 2. 机会均等 eo = equalized_odds(y_pred, y, protected_attr) audit_results['equalized_odds'] = eo # 3. 差异影响 di = disparate_impact(y, y_pred, protected_attr) audit_results['disparate_impact'] = di # 4. Theil指数 theil = theil_index(y, y_pred, protected_attr) audit_results['theil_index'] = theil # 生成报告 report = generate_fairness_report(audit_results) return audit_results, report def generate_fairness_report(results): """生成公平性报告""" report = """ === AI公平性审计报告 === 1. 统计均等: {dp[satisfied]} (差异: {dp[difference]:.3f}) 2. 机会均等: {eo[satisfied]} 3. 差异影响: {di:.3f} (阈值: 0.8) 4. Theil指数: {theil:.3f} (越接近0越好) 建议: {recommendations} """.format(**results) return report
def fair_ab_test(model_baseline, model_fair, X, y, protected_attr): """公平性A/B测试""" # 基线模型 y_pred_baseline = model_baseline.predict(X) metrics_baseline = { 'accuracy': accuracy_score(y, y_pred_baseline), 'fairness': demographic_parity(y_pred_baseline, protected_attr) } # 公平模型 y_pred_fair = model_fair.predict(X) metrics_fair = { 'accuracy': accuracy_score(y, y_pred_fair), 'fairness': demographic_parity(y_pred_fair, protected_attr) } # 对比 results = { 'baseline': metrics_baseline, 'fair': metrics_fair, 'diff': { 'accuracy': metrics_fair['accuracy'] - metrics_baseline['accuracy'], 'fairness_diff': metrics_baseline['fairness']['difference'] - metrics_fair['fairness']['difference'] } } return results
高风险系统要求:
实施清单:
就业场景要求:
实施步骤:
算法公平性要求:
AI公平性是一个复杂的挑战,需要从数据、算法到部署的全流程考虑。通过系统性的偏见检测、有效的消除技术和持续的监控,可以构建更公平的AI系统。
关键要点:
随着AI监管的加强,构建公平AI系统不仅是道德要求,也是法律义务。掌握AI公平性技术,将帮助开发者在构建AI应用时避免歧视性决策,赢得用户信任。