Standard fairness audits treat bias as a snapshot — a single-point disparity measurement at one moment in time. But in sequential decision systems (loan approvals, parole reviews, hiring pipelines, credit scoring), decisions at time \(t\) feed back into the features available at time \(t+1\).
AIBias treats algorithmic bias as a longitudinal process. It tracks:
The package ships with lending_panel, a 600-applicant ×
6-year panel of synthetic loan decisions across three racial groups.
data(lending_panel)
head(lending_panel)
#> applicant_id year race income credit_score approved
#> 1 APP_0001 2015 Hispanic 58 719 1
#> 2 APP_0001 2016 Hispanic 69 759 1
#> 3 APP_0001 2017 Hispanic 59 580 1
#> 4 APP_0001 2018 Hispanic 69 677 1
#> 5 APP_0001 2019 Hispanic 56 674 0
#> 6 APP_0001 2020 Hispanic 57 619 0# Pooled approval rates by group
tapply(lending_panel$approved, lending_panel$race, mean) |> round(3)
#> White Black Hispanic
#> 0.775 0.514 0.579Even from this simple tabulation we see a gap. But it misses the dynamic story: are disadvantaged groups less able to recover from a denial? Are gaps widening over time?
obj <- aib_build(
data = lending_panel,
id = "applicant_id",
time = "year",
group = "race",
decision = "approved"
)
print(obj)
#>
#> == AIBias Audit Object ==
#> Units : 600
#> Time points : 6 ( 2015, 2016, 2017, 2018, 2019, 2020 )
#> Groups : White, Black, Hispanic
#> Decision : approved
#>
#> Components populated:
#> ✕ bias
#> ✕ transitions
#> ✕ amplification
#> ✕ adjusted
#> ✕ bootstrapaib_describe() computes:
obj <- aib_describe(obj, ref_group = "White")
obj$bias$cumulative
#> # A tibble: 2 × 7
#> group ref_group CB_raw CB_normalized CB_smd peak_disparity time_to_peak
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <int>
#> 1 Black White -1.56 -0.261 -3.31 0.292 3
#> 2 Hispanic White -1.17 -0.196 -2.49 0.304 3The cumulative burden (CB_normalized) summarizes the
average disparity experienced across all waves — a single policy-facing
number.
Both groups show a persistent negative disparity from wave 1. The gap is relatively stable, suggesting a persistent rather than purely growing pattern — but the dynamic analysis below reveals compounding beneath the surface.
The key question for compounding bias: are disadvantaged groups less likely to recover after a denial, and less likely to retain approval?
obj <- aib_transition(obj, ref_group = "White")
# Recovery and retention gaps
obj$transitions$recovery_gap
#> # A tibble: 2 × 4
#> group p_recovery_g p_recovery_ref recovery_gap
#> <fct> <dbl> <dbl> <dbl>
#> 1 Black 0.41 0.656 -0.246
#> 2 Hispanic 0.464 0.656 -0.193
obj$transitions$retention_gap
#> # A tibble: 2 × 4
#> group p_retention_g p_retention_ref retention_gap
#> <fct> <dbl> <dbl> <dbl>
#> 1 Black 0.629 0.821 -0.192
#> 2 Hispanic 0.670 0.821 -0.151The transition plot reveals the mechanism of compounding. Despite some overall disparity in approval rates, the recovery gap is the most consequential finding: after a denial, Black applicants recover at a much lower rate than White applicants, locking them into unfavorable states.
The amplification index measures:
\[A_{g,r}(t) = B_{g,r}(t \mid 1) - B_{g,r}(t \mid 0)\]
If \(A_{g,r}(t) \neq 0\), prior decision state is modifying the group disparity — the hallmark of dynamic rather than static bias.
obj <- aib_amplify(obj, ref_group = "White")
obj$amplification$cumulative
#> # A tibble: 2 × 5
#> group A_cumulative A_mean A_max T_amplifying
#> <chr> <dbl> <dbl> <dbl> <int>
#> 1 Black 0.266 0.0533 0.288 5
#> 2 Hispanic 0.212 0.0423 0.187 5To separate “case mix” differences from residual disparity, fit a covariate-adjusted model:
obj <- aib_adjust(
obj,
formula = ~ income + credit_score,
method = "glm",
ref_group = "White"
)
# Adjusted trajectory
head(obj$adjusted$trajectory)obj <- aib_bootstrap(obj, B = 500, seed = 2024, conf = 0.95)
plot(obj, type = "trajectory") # Now includes ribbon CIsaib_audit()Run the full pipeline in one call:
result <- aib_audit(
lending_panel,
id = "applicant_id",
time = "year",
group = "race",
decision = "approved",
ref_group = "White",
bootstrap = TRUE,
B = 200,
seed = 42
)
summary(result)A decision system exhibits bias amplification for group \(g\) relative to reference group \(r\) over times \(1, \ldots, T\) if:
\(|B_{g,r}(t)| > |B_{g,r}(s)|\) for some \(t > s\) (disparity grows), and
Either \(A_{g,r}(t) = B_{g,r}(t \mid 1) - B_{g,r}(t \mid 0) \neq 0\) (prior decisions modulate current disparity), or
\(P_g(t) \neq P_r(t)\) (group transition matrices are unequal).
Proposition: If \(p_g^{11}(t) < p_r^{11}(t)\) and \(p_g^{01}(t) < p_r^{01}(t)\) for all \(t\), then under common initial conditions the favorable-decision probability for group \(g\) weakly decreases relative to group \(r\) over time, implying nonnegative cumulative disparity against group \(g\).
This distinguishes static persistent bias (constant gap) from dynamic compounding bias (self-reinforcing gap driven by the decision process itself).
| Estimand | Function | Formula |
|---|---|---|
| Bias trajectory | aib_describe() |
\(B_{g,r}(t)\) |
| Standardized trajectory | aib_describe() |
\(B^*_{g,r}(t)\) |
| Cumulative burden | aib_describe() |
\(CB_{g,r}(T)\) |
| Recovery gap | aib_transition() |
\(\Delta^{01}_{g,r}\) |
| Retention gap | aib_transition() |
\(\Delta^{11}_{g,r}\) |
| Amplification index | aib_amplify() |
\(A_{g,r}(t)\) |
| Bias persistence | aib_persistence() |
\(PB_{g,r}(c)\) |