因果公平性理论基础
1. 引言
因果公平性(Causal Fairness)使用因果推断工具来建模和解决算法歧视问题。与传统统计公平性方法不同,因果方法可以区分”可接受的差异”(由真实因果关系导致)和”不可接受的歧视”(由偏见路径导致)。1
1.1 为什么需要因果公平性
传统公平性方法存在以下局限:
| 方法 | 局限 |
|---|---|
| Fairness Through Unawareness | 忽略敏感属性,但可能包含歧视信息的代理变量 |
| Demographic Parity | 可能拒绝有用的预测信息 |
| Equalized Odds | 无法解释差异的来源 |
因果公平性可以:
- 回答”为什么”产生差异
- 区分直接歧视和间接歧视
- 指导具体的干预行动
1.2 因果公平性框架
因果公平性问题:
敏感属性 A (种族、性别等)
↓
┌───┴───┐
↓ ↓
公平路径 不公平路径
(X→Y) (A→X→Y)
↓ ↓
Y Y
↓ ↓
结果差异 = 可接受差异 + 歧视性差异
2. 反事实公平性
2.1 基础定义
反事实公平性(Counterfactual Fairness,Kusner et al., 2017)2:
定义:当且仅当对于每个个体 ,预测值在反事实世界(敏感属性改变)和现实世界中相同,则预测器是反事实公平的。
形式化表达:
其中:
- 是敏感属性
- 是原始值
- 是反事实值
- 表示在将 干预为 的反事实世界中的预测
2.2 三步推理框架
反事实公平性的计算遵循 Pearl 的因果推理框架:
反事实推理三步:
1. 溯因(Abduction)
P(U | W=w) ← 根据观测数据推断背景变量
2. 行动(Action)
P(Y_{A←a} | W=w) ← 用干预替换敏感属性
3. 预测(Prediction)
E[Y_{A←a} | W=w] ← 计算反事实结果期望
数学形式化:
给定因果模型 和观测数据 :
2.3 反事实公平性的因果图表示
反事实公平性因果图:
A (敏感属性)
↙ ↓ ↘
↓ ↓ ↓
X₁ X₂ X₃ (中介变量)
↘ ↓ ↙
Y (结果)
↓
U (未观测混杂)
反事实公平性条件:
对于任何反事实 ,满足:
这意味着 不能依赖于通过任何从 到 的路径传递的信息。
3. 路径特定反事实公平性
3.1 问题的提出
敏感属性可能同时通过”公平”和”不公平”路径影响决策:
多路径因果图:
A (敏感属性)
↙ ↓ ↘
↓ ↓ ↓
公平 中介 历史
路径 路径 路径
↓ ↓ ↓
↘ ↓ ↙
Y
问题:如果完全阻断所有路径,可能损失有用的预测信息。
3.2 路径特定公平性
路径特定反事实公平性(Chiappa, 2019)3:
核心思想:忽略沿”不公平”路径的影响,保留沿”公平”路径的信息。
定义:对于给定的路径集 ,如果:
则预测器满足路径 上的反事实公平性。
3.3 公平路径的定义
| 路径类型 | 示例 | 是否公平 |
|---|---|---|
| 直接路径 | 通常不公平 | |
| 历史歧视 | 不公平 | |
| 真实能力差异 | (是真实能力) | 可能公平 |
| 中介歧视 | (是历史偏见的结果) | 不公平 |
3.4 应用示例:信贷决策
信贷决策因果图:
种族/性别 (A)
↓
┌───────┼───────┐
↓ ↓ ↓
历史歧视 教育 真实信用
(X₁) (X₂) (X₃)
↓ ↓ ↓
└───┬───┴───────┘
↓
信用评分 (Y)
公平性分析:
- 路径 :不公平(历史歧视)
- 路径 :可能公平(真实信用差异)
- 路径 :视情况而定
4. PC-Fairness统一框架
4.1 框架概述
PC-Fairness(Wu et al., NeurIPS 2019)4:
目标:统一各种因果公平性度量,解决可识别性问题。
核心贡献:
- 形式化定义各种因果公平性度量
- 分析其可识别性条件
- 提供统一的计算框架
4.2 公平性度量的因果形式化
| 度量 | 因果定义 | 可识别性 |
|---|---|---|
| 反事实公平性 | 需完全因果模型 | |
| 路径特定公平性 | 部分可识别 | |
| 平均因果效应公平性 | $ | E[Y_{A\leftarrow 1}] - E[Y_{A\leftarrow 0}] |
4.3 可识别性条件
可识别性定理:
因果公平性度量 在以下条件下可识别:
- 后门路径阻塞:存在足够的调整集
- 前门路径:使用前门准则
- 工具变量:使用工具变量法
class PCFairnessFramework:
def __init__(self, causal_graph):
self.graph = causal_graph
def check_identifiability(self, fairness_metric, path_set=None):
"""检查公平性度量的可识别性"""
if fairness_metric == 'counterfactual':
return self._identify_counterfactual_fairness()
elif fairness_metric == 'path_specific':
return self._identify_path_specific(path_set)
elif fairness_metric == 'ace_fairness':
return self._identify_ace_fairness()
def _identify_counterfactual_fairness(self):
"""反事实公平性的可识别性"""
# 需要完整的因果模型
return self.graph.has_no_unobserved_confounders()
def _identify_path_specific(self, path_set):
"""路径特定公平性的可识别性"""
# 需要满足特定的可识别性条件
return self._check_genealogy_condition(path_set)5. 因果公平性的统计度量
5.1 条件平均因果效应(CACE)
定义:在特定条件下处理组的平均因果效应
5.2 公平性差异度量
| 度量 | 公式 | 含义 |
|---|---|---|
| 总体差异 | $E[Y | A=1] - E[Y |
| 因果差异 | 因果效应差异 | |
| 间接歧视 | 沿不公平路径的因果效应 | 历史偏见 |
| 直接歧视 | 沿直接路径的因果效应 | 即时偏见 |
5.3 分解分析
class CausalFairnessDecomposition:
def decompose(self, graph, treatment, outcome, covariates):
"""
将观测差异分解为因果和非因果成分
Total Disparity = Direct Effect + Indirect Effect + Confounding
"""
# 总差异
total = self._total_disparity(outcome, treatment)
# 直接因果效应(总直接效应)
direct_effect = self._direct_effect(
graph, treatment, outcome
)
# 间接效应(通过中介)
indirect_effect = self._indirect_effect(
graph, treatment, outcome, covariates
)
# 混杂效应
confounding = total - direct_effect - indirect_effect
return {
'total': total,
'direct': direct_effect,
'indirect': indirect_effect,
'confounding': confounding
}6. 因果公平性的因果图建模
6.1 公平性因果图的构建
class FairnessCausalGraph:
"""
构建公平性分析的因果图
节点类型:
- A: 敏感属性(种族、性别等)
- C: 合法的协变量
- M: 中介变量
- U: 未观测混杂
- Y: 决策/结果
"""
def build_graph(self, scenario='employment'):
if scenario == 'employment':
# 就业决策场景
nodes = {
'A': 'race/gender', # 敏感属性
'C': 'education', # 合法因素
'M': 'job_history', # 中介(历史偏见)
'U': 'unobserved', # 未观测混杂
'Y': 'hired' # 决策
}
edges = [
('A', 'M'), # 历史偏见
('A', 'C'), # 教育机会不平等
('C', 'M'), # 经验影响历史
('C', 'Y'), # 合法因素
('M', 'Y'), # 历史影响决策
('U', 'C'), # 混杂
('U', 'Y') # 混杂
]
elif scenario == 'lending':
# 信贷决策场景
# ...
return nodes, edges6.2 混杂控制策略
| 策略 | 方法 | 适用场景 |
|---|---|---|
| 后门调整 | $P(Y | do(A), X) = \sum_x P(Y |
| 前门调整 | 估计直接因果效应 | 无法观测混杂 |
| 工具变量 | 两阶段最小二乘 | 存在工具变量 |
6.3 反事实计算
class CounterfactualFairnessCalculator:
def compute_fairness(self, model, individual_data, sensitive_attr,
counterfactual_value):
"""
计算单个个体的反事实公平性
Steps:
1. Abduction: P(U | W=w)
2. Action: do(A = a')
3. Prediction: E[Y_{A←a'}]
"""
# Step 1: 溯因
posterior = self._compute_posterior(individual_data)
# Step 2: 行动(干预)
intervened_data = individual_data.copy()
intervened_data[sensitive_attr] = counterfactual_value
# Step 3: 预测
factual_pred = model.predict([individual_data])
counterfactual_pred = model.predict([intervened_data])
return {
'factual': factual_pred,
'counterfactual': counterfactual_pred,
'fairness_violation': abs(factual_pred - counterfactual_pred)
}7. 因果公平性算法
7.1 FairWalk算法
FairWalk(Rahman et al., 2019):
思想:在图嵌入中引入公平性约束
class FairWalk:
def fit(self, graph, sensitive_attr, embedding_dim=64):
"""
FairWalk: 公平的图嵌入
"""
# Step 1: 修改随机游走概率
def fair_walk_probability(node, neighbor, sensitive_attr):
base_prob = 1 / graph.degree(node)
# 公平性调整:减少组间差异
if graph.node[neighbor][sensitive_attr] != \
graph.node[node][sensitive_attr]:
return base_prob * fairness_penalty
return base_prob
# Step 2: 生成公平随机游走
walks = self._generate_fair_walks(
graph,
walk_prob=fair_walk_probability
)
# Step 3: Skip-gram训练
embeddings = self._train_embeddings(walks, embedding_dim)
return embeddings7.2 对抗去偏见
class AdversarialFairness:
"""
对抗学习实现因果公平性
"""
def __init__(self, predictor, adversary, lambda_fair=1.0):
self.predictor = predictor
self.adversary = adversary
self.lambda_fair = lambda_fair
def fit(self, X, Y, A):
"""
训练目标:
min_θ max_φ L_pred(Y, Ŷ) - λ L_adversary(A, Â) + λ_fair L_fair
"""
for epoch in range(n_epochs):
# 更新预测器
Y_pred = self.predictor(X)
adv_pred = self.adversary(Y_pred.detach())
pred_loss = self.criterion(Y, Y_pred)
adv_loss = self.adversary.criterion(A, adv_pred)
fair_loss = self._causal_fairness_loss(X, Y_pred, A)
pred_loss_total = pred_loss + \
self.lambda_adv * adv_loss + \
self.lambda_fair * fair_loss
pred_loss_total.backward()
# 更新对抗器
self.adversary.zero_grad()
adv_pred = self.adversary(Y_pred.detach())
adv_loss = self.adversary.criterion(A, adv_pred)
(-adv_loss).backward()
def _causal_fairness_loss(self, X, Y_pred, A):
"""
因果公平性损失
鼓励预测器不依赖于敏感属性
"""
# 使用因果干预近似
Y_pred_0 = self.predictor(self._intervene(X, A, value=0))
Y_pred_1 = self.predictor(self._intervene(X, A, value=1))
# 反事实公平性损失
return torch.mean((Y_pred_0 - Y_pred_1) ** 2)7.3 因果感知正则化
class CausalFairnessRegularizer:
"""
因果公平性正则化器
"""
def __init__(self, causal_graph, path_set):
self.graph = causal_graph
self.path_set = path_set # 不公平路径集
def fairness_loss(self, X, Y_pred, A):
"""
计算因果公平性正则化损失
L_fair = ||Y - E[Y_A]||²
其中 E[Y_A] 是沿公平路径的期望预测
"""
# 估计反事实结果
Y_counterfactual = self._estimate_counterfactual(X, A)
# 只考虑沿公平路径的影响
Y_fair = self._project_to_fair_paths(Y_counterfactual)
return torch.mean((Y_pred - Y_fair) ** 2)
def _estimate_counterfactual(self, X, A):
"""使用因果模型估计反事实"""
# ...
pass
def _project_to_fair_paths(self, Y_cf):
"""投影到公平路径"""
# ...
pass8. 因果公平性与传统公平性的联系
8.1 与统计公平性的关系
| 统计公平性 | 因果对应 | 联系 |
|---|---|---|
| Demographic Parity | 反事实版本的DP | |
| Equalized Odds | $P(Y=1 | A=0, Y^*=1) = P(Y=1 |
| ** Predictive Parity** | $P(Y^*=1 | A=0, Y=1) = P(Y^*=1 |
8.2 理论联系
定理(Anthis & Veitch, 2024)5:
满足反事实公平性的预测器自动满足Demographic Parity(在一定条件下)。
证明思路:
若 (反事实公平),则 。
9. 工具与实现
9.1 CausalFairness库
Amazon Science CausalFairnessInAction6:
# 安装
# pip install causal-fairness-in-action
from causal_fairness import CounterfactualFairness, PathSpecificFairness
from causal_fairness.datasets import load_adult
# 加载数据
data = load_adult()
# 创建因果图
graph = CounterfactualFairness.create_default_graph()
# 计算反事实公平性
cf_fairness = CounterfactualFairness(graph)
fairness_score = cf_fairness.evaluate(data, treatment='sex', outcome='income')
print(f"Counterfactual Fairness Score: {fairness_score}")
# 路径特定公平性
ps_fairness = PathSpecificFairness(
graph,
unfair_paths=['sex -> education -> occupation -> income']
)
ps_score = ps_fairness.evaluate(data)
print(f"Path-Specific Fairness Score: {ps_score}")9.2 DoWhy集成
import dowhy
from dowhy.causal_identifier import auto_identify_effect
# 定义因果图
model = dowhy.CausalModel(
data=data,
treatment='sex',
outcome='income',
common_causes=['education', 'occupation', 'hours_per_week'],
graph="""
digraph {
sex -> education;
sex -> income;
education -> occupation;
education -> income;
occupation -> income;
}
"""
)
# 识别因果效应
identified_estimand = model.identify_effect()
# 估计因果效应(公平性调整后)
estimate = model.estimate_effect(
identified_estimand,
method_name="backdoor.linear_regression"
)
print(f"Causal Effect (Sex -> Income): {estimate.value}")9.3 Fairlearn集成
from fairlearn.datasets import fetch_adult
from fairlearn.reductions import ExponentiatedGradient, DemographicParity
# 获取数据
data = fetch_adult()
# 定义公平性约束
constraint = DemographicParity()
mitigator = ExponentiatedGradient(
estimator=model,
constraints=constraint
)
# 训练公平模型
mitigator.fit(X_train, y_train, sensitive_features=A_train)
# 评估
fair_predictions = mitigator.predict(X_test)10. 实践指南
10.1 实施检查清单
fairness_implementation_checklist = """
因果公平性实施检查清单:
□ 因果图构建
□ 识别敏感属性 A
□ 识别相关变量 X
□ 定义结果 Y
□ 假设未观测混杂 U
□ 标注公平/不公平路径
□ 可识别性分析
□ 检查后门路径
□ 评估可识别性条件
□ 选择适当的估计方法
□ 公平性评估
□ 计算反事实公平性得分
□ 计算路径特定公平性
□ 对比不同方法的结果
□ 公平性优化
□ 选择公平性-准确性权衡点
□ 实施公平性干预
□ 验证干预效果10.2 注意事项
- 因果假设的重要性:因果公平性的有效性依赖于因果图假设的正确性
- 可识别性限制:某些公平性度量可能从观测数据中无法识别
- 公平-准确权衡:更强的公平性约束可能导致准确率下降
- 组内公平性:关注组内差异而非仅关注组间差异
11. 参考文献
相关主题
Footnotes
-
Kilbertus, N., et al. (2020). Avoiding Discrimination through Causal Reasoning. JMLR. ↩
-
Kusner, M., et al. (2017). Counterfactual Fairness. NeurIPS. ↩
-
Chiappa, S. (2019). Path-Specific Counterfactual Fairing. AAAI. ↩
-
Wu, Y., et al. (2019). PC-Fairness: A Unified Framework. NeurIPS. ↩
-
Anthis, J. R., & Veitch, V. (2024). Causal Context Connects Counterfactual Fairness to Robust Prediction and Group Fairness. ↩
-
Amazon Science. (2025). CausalFairnessInAction. NeurIPS 2025. ↩