The Interview Question
"You've built a model that predicts loan default. How would you ensure it's fair across different demographic groups?"
Ethics and bias are critical topics in modern data science â companies face legal, reputational, and moral consequences for biased algorithms.
Why Companies Ask This
âšī¸
Google and Microsoft are under intense scrutiny for algorithmic bias. They need data scientists who can build fair systems, understand the ethical implications of their work, and navigate complex trade-offs between accuracy and fairness.
Interviewers evaluate:
- Bias Awareness â Can you identify potential sources of bias?
- Fairness Knowledge â Do you understand different fairness definitions?
- Mitigation Skills â Can you implement bias mitigation techniques?
- Ethical Reasoning â Can you navigate complex ethical trade-offs?
- Regulatory Knowledge â Do you understand legal requirements?
The Ethics and Bias Framework
Step 1: Identify Potential Bias Sources
bias_sources = {
'historical_bias': {
'description': 'Data reflects past discrimination',
'example': 'Loan approval data from historically biased lending practices',
'mitigation': 'Debias training data, use fairness-aware algorithms',
},
'representation_bias': {
'description': 'Some groups are underrepresented in data',
'example': 'Medical training data mostly from white patients',
'mitigation': 'Collect more diverse data, use stratified sampling',
},
'measurement_bias': {
'description': 'Features are measured differently across groups',
'example': 'Credit score calculated differently by location',
'mitigation': 'Standardize measurement, validate across groups',
},
'aggregation_bias': {
'description': 'One model doesn\'t fit all groups',
'example': 'A model that works well on average but poorly for minorities',
'mitigation': 'Train separate models, use group-specific features',
},
'evaluation_bias': {
'description': 'Benchmark doesn\'t represent deployment context',
'example': 'Testing on easy examples, deploying on hard ones',
'mitigation': 'Use representative test sets, diverse evaluation',
},
'deployment_bias': {
'description': 'Model used in ways it wasn\'t designed for',
'example': 'Risk assessment model used for different decisions',
'mitigation': 'Clear documentation, usage guidelines',
},
}
Step 2: Define Fairness
fairness_definitions = {
'demographic_parity': {
'definition': 'Prediction rates should be equal across groups',
'formula': 'P(Yhat=1 | A=0) = P(Yhat=1 | A=1)',
'example': 'Loan approval rate should be equal for men and women',
'tradeoff': 'May reduce accuracy if base rates differ',
},
'equalized_odds': {
'definition': 'True positive and false positive rates should be equal',
'formula': 'TPR and FPR equal across groups',
'example': 'Among qualified applicants, approval rates should be equal',
'tradeoff': 'May not be achievable if base rates differ significantly',
},
'predictive_parity': {
'definition': 'Positive predictive value should be equal',
'formula': 'PPV = TP / (TP + FP) equal across groups',
'example': 'Among those predicted to default, actual default rate should be equal',
'tradeoff': 'Conflicts with equalized odds in some cases',
},
'calibration': {
'definition': 'Predicted probabilities should match actual outcomes',
'formula': 'P(Y=1 | Yhat=p) = p for all groups',
'example': 'A 30% predicted default rate should mean 30% actually default',
'tradeoff': 'Most intuitive but hardest to achieve',
},
'individual_fairness': {
'definition': 'Similar individuals should receive similar predictions',
'formula': 'Distance(Yhat_i, Yhat_j) <= L * Distance(X_i, X_j)',
'example': 'Similar loan applicants should get similar decisions',
'tradeoff': 'Requires defining "similarity" â subjective',
},
}
Example: Fair Loan Default Prediction
Step 1: Assess Current Bias
import pandas as pd
import numpy as np
from sklearn.metrics import confusion_matrix
def assess_fairness(y_true, y_pred, protected_attribute):
"""
Assess fairness across protected groups.
"""
groups = protected_attribute.unique()
metrics = {}
for group in groups:
mask = protected_attribute == group
group_true = y_true[mask]
group_pred = y_pred[mask]
# Confusion matrix
tn, fp, fn, tp = confusion_matrix(group_true, group_pred).ravel()
metrics[group] = {
'n_samples': len(group_true),
'approval_rate': group_pred.mean(),
'true_positive_rate': tp / (tp + fn) if (tp + fn) > 0 else 0,
'false_positive_rate': fp / (fp + tn) if (fp + tn) > 0 else 0,
'positive_predictive_value': tp / (tp + fp) if (tp + fp) > 0 else 0,
'accuracy': (tp + tn) / (tp + tn + fp + fn),
}
return metrics
def calculate_fairness_metrics(metrics):
"""
Calculate fairness metrics from group-level metrics.
"""
groups = list(metrics.keys())
# Demographic parity difference
approval_rates = [metrics[g]['approval_rate'] for g in groups]
demographic_parity_diff = max(approval_rates) - min(approval_rates)
# Equalized odds difference
tpr_diff = max(metrics[g]['true_positive_rate'] for g in groups) - \
min(metrics[g]['true_positive_rate'] for g in groups)
fpr_diff = max(metrics[g]['false_positive_rate'] for g in groups) - \
min(metrics[g]['false_positive_rate'] for g in groups)
return {
'demographic_parity_difference': demographic_parity_diff,
'equalized_odds_tpr_difference': tpr_diff,
'equalized_odds_fpr_difference': fpr_diff,
'disparate_impact_ratio': min(approval_rates) / max(approval_rates),
}
Step 2: Mitigate Bias
class FairnessMitigator:
"""
Various techniques for mitigating bias in ML models.
"""
def __init__(self):
self.methods = {
'pre_processing': self.pre_processing_methods,
'in_processing': self.in_processing_methods,
'post_processing': self.post_processing_methods,
}
def pre_processing_methods(self, X, y, protected):
"""
Modify training data to reduce bias.
"""
methods = {
'reweighing': self.reweighing,
'disparate_impact_remover': self.disparate_impact_remover,
'learning_fair_representations': self.learning_fair_representations,
}
return methods
def reweighing(self, X, y, protected):
"""
Assign weights to training examples to achieve fairness.
"""
weights = np.ones(len(y))
for group in protected.unique():
group_mask = protected == group
for label in y.unique():
# Weight = expected count / actual count
expected = (group_mask.sum() * (y == label).sum()) / len(y)
actual = (group_mask & (y == label)).sum()
weights[group_mask & (y == label)] = expected / actual
return weights
def disparate_impact_remover(self, X, protected, repair_level=1.0):
"""
Modify features to remove disparate impact.
"""
X_repaired = X.copy()
for col in X.select_dtypes(include=[np.number]).columns:
# Compute quantiles for each group
group_quantiles = {}
for group in protected.unique():
group_mask = protected == group
group_quantiles[group] = X.loc[group_mask, col].rank(pct=True)
# Repair: move each group's distribution toward median
median_quantile = pd.DataFrame(group_quantiles).median(axis=1)
for group in protected.unique():
group_mask = protected == group
group_values = X.loc[group_mask, col]
target_quantile = median_quantile[group_mask]
# Interpolate to target quantile
repaired = group_values.rank(pct=True) * (1 - repair_level) + \
target_quantile * repair_level
X_repaired.loc[group_mask, col] = repaired
return X_repaired
def in_processing_methods(self):
"""
Modify learning algorithm to incorporate fairness constraints.
"""
return {
'adversarial_debiasing': 'Train model to be fair while maintaining accuracy',
'prejudice_remover': 'Add fairness regularization term to loss function',
'exponentiated_gradient': 'Use constrained optimization for fairness',
}
def post_processing_methods(self, y_pred, protected):
"""
Adjust predictions after model training.
"""
methods = {
'equalized_odds_postprocessing': self.equalized_odds_postprocessing,
'threshold_adjustment': self.threshold_adjustment,
}
return methods
def threshold_adjustment(self, y_scores, protected, target_metric='equalized_odds'):
"""
Find group-specific thresholds that achieve fairness.
"""
from scipy.optimize import minimize_scalar
thresholds = {}
for group in protected.unique():
group_mask = protected == group
group_scores = y_scores[group_mask]
# Optimize threshold for fairness metric
def objective(threshold):
predictions = (group_scores >= threshold).astype(int)
# Implement fairness metric here
return abs(predictions.mean() - 0.5) # Example: target 50% approval
result = minimize_scalar(objective, bounds=(0, 1), method='bounded')
thresholds[group] = result.x
return thresholds
Google's AI Principles
google_ai_principles = {
'be_socially_beneficial': 'Avoid creating or reinforcing unfair bias',
'avoid_creating_or_reinforcing_unfair_bias': {
'action': 'Test for unfair bias and address it',
'example': 'Regular fairness audits of search results',
},
'be_accountable_to_people': 'Provide explanations for decisions',
'incorporate_privacy_design_principles': 'Protect user data',
'uphold_high_standards_of_scientific_excellence': 'Rigorous research',
}
Microsoft's Responsible AI Principles
microsoft_responsible_ai = {
'fairness': 'AI systems should treat all people fairly',
'reliability_safety': 'AI systems should perform reliably and safely',
'privacy_security': 'AI systems should be secure and respect privacy',
'inclusiveness': 'AI should empower everyone',
'transparency': 'AI systems should be understandable',
'accountability': 'People should be accountable for AI systems',
}
Common Mistakes to Avoid
â ī¸
These mistakes can have serious legal and ethical consequences:
- Ignoring protected attributes â Not including them doesn't remove bias
- Optimizing only for accuracy â Accuracy can mask unfairness
- Assuming fairness is binary â It's a spectrum with trade-offs
- Not testing across groups â Average metrics hide disparities
- Not documenting decisions â Auditability requires documentation
- Not monitoring post-deployment â Bias can emerge over time