Home▸Articles▸Privacy, Fairness, and Compliance

ML Fairness

Building fair ML systems - bias detection, fairness metrics, mitigation strategies, and responsible AI practices.

mysimulator teamUpdated 2026-01≈ 5 min read▶ Open the simulation

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:

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

  1. Identify protected attributes - Race, gender, age, disability, etc.
  2. Audit for bias - Measure disparities in current system
  3. Choose fairness criteria - Based on context and values
  4. Understand trade-offs - Fairness vs accuracy, fairness vs fairness
  5. Select mitigation approach - Pre, in, or post-processing
  6. Implement and measure - Quantify improvement
  7. Monitor continuously - Fairness can degrade over time
  8. Document decisions - Justify choices for stakeholders
  9. Engage stakeholders - Include affected communities
  10. 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

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

Further Reading

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

What did you find?

Add reproduction steps (optional)