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