ML fairness ensures models don't discriminate against protected groups. Bias can enter through data, features, labels, or model design - often unintentionally. Fair ML requires measuring disparities, understanding trade-offs between fairness definitions, and implementing mitigation strategies that balance accuracy with equity.
Where It Is Used
Fairness is critical in high-stakes decisions:
- Lending: Credit decisions, loan approvals
- Hiring: Resume screening, candidate ranking
- Healthcare: Treatment recommendations, risk scores
- Criminal justice: Risk assessment, sentencing
- Insurance: Premium pricing, claim decisions
- Housing: Rental applications, property valuations
- Advertising: Ad targeting, opportunity distribution
Regulations: GDPR, ECOA, Fair Housing Act, EEOC guidelines.
Sources of Bias
| Source | Description | Example |
|---|---|---|
| Historical bias | Past discrimination in data | Hiring data reflects past discrimination |
| Representation bias | Skewed training data | Underrepresented minorities |
| Measurement bias | Proxies for protected attributes | Zip code as proxy for race |
| Aggregation bias | One model for diverse groups | Single risk model for all ages |
| Evaluation bias | Biased test sets | Benchmarks not representative |
| Deployment bias | Misuse in deployment | Model used for unintended purpose |
Fairness Definitions
No single definition of fairness - they can conflict.
Group fairness metrics:
| Metric | Definition | When to Use |
|---|---|---|
| Demographic parity | Equal positive rates across groups | When selection rates should be equal |
| Equalized odds | Equal TPR and FPR across groups | When error rates should be equal |
| Equal opportunity | Equal TPR across groups | When false negatives are costly |
| Calibration | Same probability → same outcome rate | When probabilities used directly |
| Predictive parity | Equal PPV across groups | When precision matters |
def demographic_parity(y_pred, protected_attribute):
"""Positive rate difference between groups."""
group_a = y_pred[protected_attribute == 0].mean()
group_b = y_pred[protected_attribute == 1].mean()
return abs(group_a - group_b)
def equalized_odds(y_true, y_pred, protected_attribute):
"""TPR and FPR difference between groups."""
results = {}
for group in [0, 1]:
mask = protected_attribute == group
tpr = y_pred[(mask) & (y_true == 1)].mean()
fpr = y_pred[(mask) & (y_true == 0)].mean()
results[group] = {'tpr': tpr, 'fpr': fpr}
tpr_diff = abs(results[0]['tpr'] - results[1]['tpr'])
fpr_diff = abs(results[0]['fpr'] - results[1]['fpr'])
return tpr_diff, fpr_diff
Individual fairness: Similar individuals should receive similar predictions.
def individual_fairness(X, y_pred, similarity_metric, threshold=0.1):
"""Similar inputs should have similar outputs."""
violations = 0
for i in range(len(X)):
for j in range(i+1, len(X)):
input_similarity = similarity_metric(X[i], X[j])
output_difference = abs(y_pred[i] - y_pred[j])
if input_similarity > 0.9 and output_difference > threshold:
violations += 1
return violations
What You Do in Practice
- Identify protected attributes - Race, gender, age, disability, etc.
- Audit for bias - Measure disparities in current system
- Choose fairness criteria - Based on context and values
- Understand trade-offs - Fairness vs accuracy, fairness vs fairness
- Select mitigation approach - Pre, in, or post-processing
- Implement and measure - Quantify improvement
- Monitor continuously - Fairness can degrade over time
- Document decisions - Justify choices for stakeholders
- Engage stakeholders - Include affected communities
- Plan for appeals - Process for challenging decisions
Bias Mitigation Strategies
Pre-processing (change data):
# Resampling to balance groups
from imblearn.over_sampling import SMOTE
def balance_groups(X, y, protected):
# Oversample underrepresented group
smote = SMOTE()
X_balanced, y_balanced = smote.fit_resample(X, y)
return X_balanced, y_balanced
# Remove biased features
def remove_proxies(df, proxy_features):
return df.drop(columns=proxy_features)
In-processing (change model):
# Fairness constraints during training
from fairlearn.reductions import ExponentiatedGradient, DemographicParity
constraint = DemographicParity()
mitigator = ExponentiatedGradient(
estimator=LogisticRegression(),
constraints=constraint
)
mitigator.fit(X_train, y_train, sensitive_features=A_train)
Post-processing (change predictions):
# Threshold adjustment per group
def equalize_odds_threshold(y_prob, y_true, protected):
# Find optimal threshold per group to equalize TPR/FPR
thresholds = {}
for group in [0, 1]:
mask = protected == group
# Grid search for threshold
best_threshold = find_optimal_threshold(
y_prob[mask], y_true[mask],
target_tpr=0.8 # Target TPR
)
thresholds[group] = best_threshold
return thresholds
Evaluation and Metrics
| Metric | Target | Notes |
|---|---|---|
| Disparate impact ratio | > 0.8 | 80% rule |
| Demographic parity diff | < 0.1 | Common threshold |
| Equalized odds diff | < 0.1 | Both TPR and FPR |
| Calibration difference | < 0.05 | Probability accuracy |
Fairness-accuracy trade-off:
def pareto_frontier(models_results):
"""Find models on fairness-accuracy frontier."""
frontier = []
for model in models_results:
accuracy = model['accuracy']
fairness = model['fairness_score'] # Higher is fairer
# Check if dominated by any other model
dominated = False
for other in models_results:
if (other['accuracy'] > accuracy and
other['fairness_score'] > fairness):
dominated = True
break
if not dominated:
frontier.append(model)
return frontier
Failure Modes and Debugging Checklist
- [ ] Proxy discrimination: Protected attribute inferred from other features
- [ ] Feedback loops: Biased predictions create biased data
- [ ] Simpson's paradox: Fair overall but unfair in subgroups
- [ ] Label bias: Ground truth labels themselves biased
- [ ] Sampling bias: Test set not representative
- [ ] Feature leakage: Protected attribute leaked through features
- [ ] Intersectionality ignored: Only checking single attributes
- [ ] Wrong fairness metric: Metric doesn't match use case
Production Checklist
Before deployment: - [ ] Protected attributes identified - [ ] Fairness metrics selected and justified - [ ] Bias audit completed - [ ] Mitigation applied and validated - [ ] Documentation complete - [ ] Legal review completed - [ ] Stakeholder sign-off obtained
After deployment: - [ ] Fairness metrics monitored - [ ] Disparities tracked over time - [ ] Feedback mechanism for complaints - [ ] Regular re-auditing scheduled - [ ] Model updates reviewed for fairness - [ ] Incident response process defined
Governance: - [ ] Responsible AI board review - [ ] Ethics guidelines followed - [ ] Transparency reports published - [ ] Appeals process established
Tools and Stack
| Category | Tools |
|---|---|
| Fairness libraries | Fairlearn, AIF360, What-If Tool |
| Audit tools | Aequitas, Themis |
| Explainability | SHAP, LIME (for fairness debugging) |
| Monitoring | Custom dashboards, model cards |
| Documentation | Model cards, datasheets |
Example Mini-Case
Scenario: Bank loan approval model showing disparate impact by race.
Audit findings: - Approval rate: 65% overall - Group A: 70% approval rate - Group B: 55% approval rate - Disparate impact ratio: 0.79 (below 0.8 threshold)
Mitigation approach: 1. Remove zip code (proxy for race) 2. Apply in-processing constraints (Fairlearn) 3. Post-processing threshold adjustment 4. Validate on holdout set
Results after mitigation:
| Metric | Before | After |
|---|---|---|
| Overall accuracy | 82% | 80% |
| Group A approval | 70% | 66% |
| Group B approval | 55% | 63% |
| Disparate impact | 0.79 | 0.95 |
Key learnings: - Small accuracy drop for significant fairness gain - Multiple mitigation approaches combined - Continuous monitoring essential - Stakeholder communication critical
Related Pages
- Index: ML Field Guide
- Binary Classification
- Model Monitoring
- Feature Engineering Fundamentals
Further Reading
- Fairlearn Documentation
- AI Fairness 360
- Fairness and Machine Learning Book
- Model Cards for Model Reporting
Try it live
Everything above runs in your browser — open AI Fairness Simulator: Demographic Parity & Simulation Speed and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.
▶ Open AI Fairness Simulator: Demographic Parity & Simulation Speed simulation