Skip to content
SDB
Responsible AI

Chapter 02 · intermediate · 35 min

Fairness & Inclusiveness

Bias taxonomy, fairness metrics, detection techniques, and mitigation strategies with Fairlearn and AIF360

Subhendu Datta BhowmikAI Tutorials

The Bias Taxonomy

Algorithmic bias is not a single problem — it manifests at multiple stages of the AI lifecycle:

Bias TypeWhere It OriginatesExample
Historical biasReflects past discrimination in dataResume model trained on historical hires where women were underrepresented
Representation biasUnderrepresentation of groups in training dataFacial recognition trained on 80% lighter-skinned faces
Measurement biasProxy variables or flawed measurementsUsing zip code as a proxy for creditworthiness (correlated with race)
Aggregation biasOne model for all groups when subgroup differences matterSingle diabetes prediction model ignoring ethnic differences in HbA1c levels
Evaluation biasBenchmarks that don't represent all groupsTesting OCR only on English text from Western documents
Deployment biasModel used in contexts it wasn't designed forUsing a sentiment model trained on product reviews for political speech

Protected Characteristics

Anti-discrimination law protects specific sensitive attributes. AI systems must not discriminate — directly or via proxies — based on:

  • EU GDPR / Human Rights: race, ethnicity, gender, age, disability, religion, sexual orientation, national origin
  • US Civil Rights: race, color, religion, sex, national origin, age (40+), disability

Proxy discrimination: even without using protected attributes directly, a model can discriminate if it uses correlated features (zip code ↔ race; name ↔ gender; job title ↔ gender).

ISO 42001 — A.7.3 (Bias in Data)

ISO 42001 control A.7.3 requires organizations to:

  1. Assess data for potential bias and representational gaps
  2. Document data provenance, collection methods, and known limitations
  3. Implement bias detection before and during model training
  4. Maintain records of bias assessments for audit

Fairness Metrics

Let AA = sensitive attribute (e.g., gender: A=0A=0 female, A=1A=1 male), Y^\hat{Y} = prediction, YY = true label.

Demographic Parity (Statistical Parity)

P(Y^=1A=0)=P(Y^=1A=1)P(\hat{Y}=1 | A=0) = P(\hat{Y}=1 | A=1)

The positive prediction rate must be equal across groups. Used when ground truth labels may themselves be biased.

Disparate Impact Ratio (80% rule, EEOC): DIR=P(Y^=1A=minority)P(Y^=1A=majority)0.8\text{DIR} = \frac{P(\hat{Y}=1 | A=\text{minority})}{P(\hat{Y}=1 | A=\text{majority})} \geq 0.8

A DIR below 0.8 signals potential illegal discrimination in US employment law.

Equal Opportunity

P(Y^=1Y=1,A=0)=P(Y^=1Y=1,A=1)P(\hat{Y}=1 | Y=1, A=0) = P(\hat{Y}=1 | Y=1, A=1)

Equal true positive rates — qualified individuals of all groups are equally likely to be identified as qualified. Prioritized when false negatives are the main concern (not hiring a qualified candidate).

Equalized Odds

P(Y^=1Y=y,A=0)=P(Y^=1Y=y,A=1)y{0,1}P(\hat{Y}=1 | Y=y, A=0) = P(\hat{Y}=1 | Y=y, A=1) \quad \forall y \in \{0,1\}

Both TPR and FPR must be equal across groups. Stronger than equal opportunity. Prioritized in criminal justice (equal false positive rates = equal wrongful conviction rates).

The Fairness-Accuracy Trade-off

Chouldechova (2017) and Kleinberg et al. (2016) proved that when base rates differ between groups, it is mathematically impossible to simultaneously satisfy:

  • Demographic parity
  • Equal opportunity
  • Calibration (predicted probabilities are accurate)

Organizations must explicitly choose which fairness criteria matter most for their use case, document that choice, and accept the trade-offs.

Bias Detection and Mitigation with Fairlearn and AIF360python
# pip install fairlearn aif360 scikit-learn pandas numpy matplotlib

# ─── 1. Load and Inspect Data for Bias ───────────────────────
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler

# Adult Income dataset (classic fairness benchmark)
from sklearn.datasets import fetch_openml
data = fetch_openml("adult", version=2, as_frame=True)
df = data.frame.copy()

# Target: income >50K (1) or <=50K (0)
df['income_binary'] = (df['class'] == '>50K').astype(int)

# Sensitive attribute: sex
df['sex_binary'] = (df['sex'] == 'Male').astype(int)  # 1=Male, 0=Female

features = ['age', 'educational-num', 'hours-per-week', 'capital-gain', 'capital-loss']
X = df[features].fillna(0)
y = df['income_binary']
sensitive = df['sex_binary']

X_train, X_test, y_train, y_test, s_train, s_test = train_test_split(
    X, y, sensitive, test_size=0.3, random_state=42, stratify=y)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# ─── 2. Train Baseline Model ──────────────────────────────────
model = LogisticRegression(max_iter=1000, random_state=42)
model.fit(X_train_scaled, y_train)
y_pred = model.predict(X_test_scaled)
y_prob = model.predict_proba(X_test_scaled)[:, 1]

# ─── 3. Compute Fairness Metrics ─────────────────────────────
from fairlearn.metrics import (
    MetricFrame,
    demographic_parity_difference,
    demographic_parity_ratio,
    equalized_odds_difference,
    selection_rate,
    true_positive_rate,
    false_positive_rate,
)
from sklearn.metrics import accuracy_score, precision_score, recall_score

metrics = {
    "accuracy": accuracy_score,
    "precision": precision_score,
    "recall": recall_score,
    "selection_rate": selection_rate,
    "true_positive_rate": true_positive_rate,
    "false_positive_rate": false_positive_rate,
}

mf = MetricFrame(
    metrics=metrics,
    y_true=y_test,
    y_pred=y_pred,
    sensitive_features=s_test,
)

print("Fairness Metrics by Gender:")
print(mf.by_group.to_string())
print(f"\nDemographic Parity Difference: {demographic_parity_difference(y_test, y_pred, sensitive_features=s_test):.4f}")
print(f"Demographic Parity Ratio:       {demographic_parity_ratio(y_test, y_pred, sensitive_features=s_test):.4f}")
print(f"Equalized Odds Difference:      {equalized_odds_difference(y_test, y_pred, sensitive_features=s_test):.4f}")

# Check 80% rule (EEOC Disparate Impact)
sel_male   = y_pred[s_test == 1].mean()
sel_female = y_pred[s_test == 0].mean()
dir_ratio = sel_female / sel_male
print(f"\nSelection rates: Male={sel_male:.3f}, Female={sel_female:.3f}")
print(f"Disparate Impact Ratio: {dir_ratio:.3f} {'(PASS ≥0.8)' if dir_ratio >= 0.8 else '(FAIL <0.8 — potential discrimination)'}")

# ─── 4. Pre-processing Mitigation: Reweighting ────────────────
from aif360.datasets import BinaryLabelDataset
from aif360.algorithms.preprocessing import Reweighing

# Prepare AIF360 dataset
df_aif = pd.DataFrame(X_train, columns=features)
df_aif['income'] = y_train.values
df_aif['sex'] = s_train.values

aif_dataset = BinaryLabelDataset(
    df=df_aif,
    label_names=['income'],
    protected_attribute_names=['sex'],
)

# Reweighing: assign instance weights to equalize representation
RW = Reweighing(unprivileged_groups=[{'sex': 0}],
                privileged_groups=[{'sex': 1}])
RW.fit(aif_dataset)
rw_dataset = RW.transform(aif_dataset)
sample_weights = rw_dataset.instance_weights

model_rw = LogisticRegression(max_iter=1000, random_state=42)
model_rw.fit(X_train_scaled, y_train, sample_weight=sample_weights)
y_pred_rw = model_rw.predict(X_test_scaled)

print("\nAfter Reweighing:")
dpd_rw = demographic_parity_difference(y_test, y_pred_rw, sensitive_features=s_test)
print(f"  Demographic Parity Difference: {dpd_rw:.4f} (was {demographic_parity_difference(y_test, y_pred, sensitive_features=s_test):.4f})")
print(f"  Accuracy: {accuracy_score(y_test, y_pred_rw):.4f} (was {accuracy_score(y_test, y_pred):.4f})")

# ─── 5. Post-processing Mitigation: Threshold Optimization ────
from fairlearn.postprocessing import ThresholdOptimizer
from fairlearn.reductions import ExponentiatedGradient, DemographicParity

# Exponentiated Gradient (in-processing): fair constraint during training
constraint = DemographicParity()
mitigator = ExponentiatedGradient(
    LogisticRegression(max_iter=1000),
    constraints=constraint,
)
mitigator.fit(X_train_scaled, y_train, sensitive_features=s_train)
y_pred_eg = mitigator.predict(X_test_scaled)

print("\nAfter Exponentiated Gradient (DemographicParity constraint):")
dpd_eg = demographic_parity_difference(y_test, y_pred_eg, sensitive_features=s_test)
print(f"  Demographic Parity Difference: {dpd_eg:.4f}")
print(f"  Accuracy: {accuracy_score(y_test, y_pred_eg):.4f}")

# ─── 6. Fairness Report (ISO 42001 A.6.2.3 evidence) ─────────
print("\n" + "="*60)
print("FAIRNESS AUDIT REPORT — ISO 42001 Control A.6.2.3")
print("="*60)
print(f"Model: Logistic Regression | Dataset: Adult Income (UCI)")
print(f"Sensitive Attribute: sex (Male=1, Female=0)")
print(f"\nBefore mitigation:")
print(f"  Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"  DPD: {demographic_parity_difference(y_test, y_pred, sensitive_features=s_test):.4f}")
print(f"  DIR: {dir_ratio:.4f} {'PASS' if dir_ratio >= 0.8 else 'FAIL (requires mitigation)'}")
print(f"\nAfter mitigation (Exponentiated Gradient):")
print(f"  Accuracy: {accuracy_score(y_test, y_pred_eg):.4f}")
print(f"  DPD: {dpd_eg:.4f}")
print(f"\nRecommendation: {'Continue to monitoring' if abs(dpd_eg) < 0.05 else 'Further review required'}")

Mitigation Strategies

Pre-processing (Fix the Data)

TechniqueHow It WorksProsCons
ResamplingOversample minority group; undersample majoritySimpleMay lose data; may overfit
ReweightingAssign higher loss weights to underrepresented groupsPreserves dataWeight selection can be tricky
Data augmentationGenerate synthetic samples for underrepresented groupsMore dataQuality of synthetic data
Label correctionCorrect known label biases using domain knowledgeDirectly addresses root causeRequires expert knowledge

In-processing (Fix the Model)

TechniqueHow It Works
Fairness constraintsAdd fairness as an optimization constraint (Exponentiated Gradient)
Adversarial debiasingJointly train predictor + adversary that tries to predict sensitive attribute from representations
Fair representation learningLearn embeddings that are invariant to sensitive attributes
Meta-fair algorithmDirectly optimize a chosen fairness metric

Post-processing (Fix the Outputs)

TechniqueHow It Works
Threshold calibrationSet different decision thresholds per group to equalize FPR/TPR
Reject option classificationHuman review for borderline predictions near the decision boundary
Calibrated equal oddsPlatt-scale per group then adjust thresholds

Implementation Checklist (ISO 42001 A.7.3 / A.6.2.3)

  • Document all sensitive attributes relevant to the use case
  • Compute group-level metrics (selection rate, TPR, FPR) before deployment
  • Calculate Disparate Impact Ratio — flag if < 0.8
  • Apply appropriate mitigation technique(s)
  • Re-evaluate metrics after mitigation and document trade-offs
  • Set up automated fairness monitoring in production
  • Establish appeals/redress process for affected individuals

Knowledge check

A loan approval model achieves 92% accuracy overall, but approves 78% of majority-group applicants who qualify versus only 61% of minority-group applicants who qualify. Which fairness metric is violated?

Summary

  • Bias has six root causes: historical, representation, measurement, aggregation, evaluation, and deployment bias — each requiring different interventions
  • Fairness definitions are incompatible: demographic parity, equal opportunity, and equalized odds cannot all be satisfied simultaneously when base rates differ
  • Disparate Impact Ratio < 0.8 triggers legal concern under US employment law; document DIR for every high-stakes model
  • Mitigation strategies span the full pipeline: reweighting data (pre-processing), fairness constraints during training (in-processing), and threshold calibration (post-processing)
  • ISO 42001 A.7.3 mandates bias assessment in training data; A.6.2.3 requires fairness testing throughout the lifecycle
  • Fairness monitoring must continue in production — distribution shifts can introduce new biases after deployment

Next: Transparency & Explainability — making AI decisions understandable with LIME, SHAP, and model cards.

Responsible AI