R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
209: Fairness Metrics for Predictive Models in R
Imagine you're managing a hiring process for a tech company. You've decided to be "objective," so you build a tool that screens resumes. On paper, the tool is brilliant—it has 90% accuracy. But after a month, you notice something unsettling: the tool is recommending 80% of male candidates for interviews, but only 20% of female candidates, even though the pool of applicants was split 50/50. Now you're in a bind. Is the tool reflecting a real difference in skill, or is it just echoing the biases of the historical data it was trained on?
This is the core of fairness metrics. In R, we don't just care if the model is "right" on average; we care about how the errors are distributed across different groups. Let's map that hiring analogy to the technical concepts we'll use in the code:
- The Protected Attribute: In our analogy, this is gender. In your code, this is the column you want to ensure doesn't unfairly influence the outcome (like race, age, or zip code).
- Demographic Parity: This is the "80% vs 20%" observation. It asks: "Is the probability of a positive outcome the same for all groups, regardless of their actual qualifications?"
- Equalized Odds: This is more nuanced. It asks: "Of the people who are actually qualified, does the model identify them at the same rate regardless of their group?" If the model misses qualified women more often than qualified men, you've failed this metric.
The Illusion of Overall Accuracy
I've seen a lot of junior devs make the mistake of reporting a high AUC or Accuracy score and calling it a day. The problem is that high overall accuracy can hide systemic failure for a minority group. If 95% of your users are from Group A and 5% are from Group B, your model could be 0% accurate for Group B and you'd still have a "95% accurate" model. That's not a success; it's a liability.
To handle this in R, I highly recommend the fairmodels package. It integrates beautifully with caret and tidymodels, allowing you to wrap your existing model and audit it without rewriting your entire pipeline.
Auditing a Loan Approval Model
Let's look at a concrete example. Suppose we have a model predicting whether a loan should be approved. We want to make sure the model isn't discriminating based on a protected attribute, like age_group.
library(fairmodels)
library(caret)
# Let's assume 'loan_model' is already trained and 'test_data' contains our holdout set
# We'll use 'age_group' as our protected attribute
# 1. Generate predictions
predictions <- predict(loan_model, test_data)
actuals <- test_data$loan_status
# 2. Wrap the model in a fairmodels object
# This is where the magic happens. We tell it which column is the protected one.
fmodel <- fairmodels(loan_model,
data = test_data,
protected = test_data$age_group,
outcome = actuals)
# 3. View the fairness metrics
print(fmodel)
When you run this, you'll see a set of ratios. In fairness auditing, a ratio of 1.0 is perfect parity. If you see a "Statistical Parity" ratio of 0.6, it means the protected group is receiving the positive outcome at only 60% of the rate of the privileged group. That's a red flag you can't ignore.
Visualizing the Gap
Numbers are fine, but stakeholders usually need a visual to actually "feel" the bias. The plot_fairness function in R is your best friend here. It allows you to see exactly where the disparity lies—whether it's in the false positive rate (giving loans to people who can't pay them back) or the false negative rate (denying loans to people who are actually creditworthy).
# This produces a comprehensive plot of various fairness metrics
plot_fairness(fmodel)
If you see that the False Negative Rate is significantly higher for the "Young" age group, your model is essentially "stricter" with young people than it is with older people, even when their financial profiles are identical. That's the kind of insight that saves a company from a lawsuit or a PR disaster.
Choosing Your Definition of Fairness
Here is the hard truth: you often cannot satisfy every fairness metric simultaneously. There is a mathematical trade-off between Demographic Parity and Predictive Parity. If you force the outcomes to be equal (Demographic Parity) but the underlying ground-truth distributions are different, you'll inevitably sacrifice some accuracy or introduce other types of unfairness.
As an engineer, your job isn't to find a "perfect" number, but to surface these trade-offs to the product owners. You provide the metrics; they provide the policy decision on which type of fairness is most critical for the specific business case.
📋 Practical Task
Auditing Gender Bias in a Mortgage Approval Pipeline
You have been handed a pre-trained mortgage approval model and a test dataset. Your task is to determine if the model exhibits gender bias and identify specifically which metric (Statistical Parity or Equal Opportunity) is being violated.
Setup:
# Load necessary libraries
library(fairmodels)
library(caret)
# Create a dummy dataset for the exercise
set.seed(42)
n <- 1000
test_data <- data.frame(
gender = sample(c("Male", "Female"), n, replace = TRUE),
income = rnorm(n, 50000, 15000),
credit_score = rnorm(n, 700, 50)
)
# Simulate a biased ground truth
test_data$approved <- ifelse(test_data$gender == "Male" & test_data$credit_score > 680, 1,
ifelse(test_data$gender == "Female" & test_data$credit_score > 720, 1, 0))
# Create a simple model that mirrors this bias
loan_model <- glm(approved ~ gender + income + credit_score, data = test_data, family = binomial)
Your Requirements:
- Use the
fairmodelspackage to wrap theloan_model. - Identify
genderas the protected attribute. - Calculate the fairness metrics and print them to the console.
- Generate a fairness plot to visualize the disparity.
- Based on the output, write a short comment in your code explaining whether the model satisfies Statistical Parity (equal outcome rates) or Equal Opportunity (equal true positive rates).
There are no comments for now.