This release turns fairGATE from a gated mixture of experts trained
under a fairness penalty into a method that corrects an independently
fitted prediction model, for binary and continuous outcomes and for any
number of protected groups. Every change since 0.1.1 is listed below. No
exported function or argument of 0.1.1 has been removed or renamed, and
new arguments of train_gnn() follow the old ones, so calls
written for 0.1.1 still run. The changes that can alter their results or
the structure of their output are listed under “Breaking changes”.
Version numbers 0.2.0 to 0.5.0 that appear in the help pages and tests are internal development versions that were not released on CRAN; 1.0.0 is the first release to contain their changes.
fairgate_base_learner() fits a cross-fitted base
learner without the protected attribute: 5-fold out-of-fold scores for
training rows and a fit on all training rows for held-out rows, so that
no training row is scored by a model that saw its outcome. The learner
is selectable: base_learner = "xgboost" (gradient-boosted
trees, package xgboost) or base_learner = "nn" (a torch
multilayer perceptron). Each has its own hyperparameter grid, listed by
fairgate_base_grid().fairgate_tune_base_learner() tunes either learner on an
inner split, by grid or seeded random search with early stopping on the
validation slice, and selects by validation loss; AUC or R-squared is
reported beside it. Fixed hyperparameters can be passed instead.train_gnn(base_score = , coupling = ) corrects the
supplied base scores. With coupling = "residual" the gate
weights the base learner and the experts, each expert proposing a
correction to the base score; with coupling = "expert" the
base score is one component of the mixture; with
coupling = "offset" the mixture is added to the base score.
The expert output layers start at zero, so the untrained model is
exactly the base learner, and an individual routed entirely to the base
learner receives its score back exactly.fairgate() runs the whole method in one call: the base
learner, the disparity signal, a search over 48 seeded random
configurations of fairgate_space() scored on an inner
split, selection of the configuration with the smallest worst-group
disparity among those within 0.01 of the best validation AUC or
R-squared, and the final fit on every partition. The defaults are those
of the accompanying study. fairgate_draw_configs() returns
the configurations searched.family = "gaussian"), with
squared-error loss and a penalty on outcome-stratified conditional mean
predictions (n_strata strata, five by default in
fairgate()).crossed_groups
(fairgate_crossed_plan(),
fairgate_crossed_penalty()).penalty: the
random-effects between-group variance component (DerSimonian and Laird),
which corrects the spread of group means for their sampling noise and is
the new default; the variance of the group means of earlier versions
("variance"); and a thresholded worst-group penalty
("thresholded") on the gaps in soft true- and
false-positive rates at the prevalence-matched threshold, or on the
worst group’s conditional mean gap for a continuous outcome
(fairgate_threshold_plan(),
fairgate_threshold_penalty(),
fairgate_group_gap_penalty()). lambda_thr adds
the thresholded term to a variance-component penalty;
reference_group names the reference group.fairgate_penalty_from_cells(),
fairgate_penalty_plan() and
fairgate_fair_penalty().intervention_cost charges the mean absolute link-scale
distance from the base learner, so that people are moved only where the
fairness gain justifies it.fairgate_disparity_target() computes, for each training
person, the signed direction in which moving their score would close
their group’s gap to the reference group, weighted by their leverage on
the decision. A cross-fitted prediction of this target from the features
and the base score can be given to the gate (gate_signal);
the protected attribute itself is never an input to the base learner,
the gate or the experts.gate = "sparsemax" or
"entmax15", fairgate_gate_map()), a
routing-balance regulariser (balance) and an adversary on
the routing weights (adversary) are available as
options.splits accepts precomputed partitions, so several
models can be compared on identical data.standardise,
impute) are computed from the training rows of each
partition only.early_stopping, es_prop,
es_min_epochs, es_patience) on a slice of the
training rows stratified on outcome and group, with an optional trailing
moving average of the monitored objective (es_smooth).alpha and lambda_max add an auxiliary
per-expert objective on a ladder of fairness weights
(fairgate_lambda_ladder()).attribution, a per-person export for every held-out
row: base score, prediction, adjustment, base weight and routing
weights.interval_reps,
interval_epochs, interval_level; columns
adj_lo, adj_hi, adj_sd).
fairgate_export() returns the export of a
fairgate() fit, flags intervals that exclude zero, and
optionally writes it to a CSV file.fairgate_group_disparity() reports per-group,
worst-group, joint and pooled separation disparity (average odds
difference, or conditional mean prediction difference in outcome
standard deviations), with an optional minimum-cell rule.base_weight) and, with sparse
gates, the number of active components (n_active) and
whether a person was routed to the base learner alone
(base_only), so that who is corrected, by which expert and
by how much can be tabulated by group. The interfaces of
analyse_experts(), analyse_gnn_results() and
plot_sankey() are unchanged.performance_summary reports the mean, standard
deviation and 2.5th and 97.5th percentiles across partitions, with
per-partition values in performance_by_split.train_gnn() also returns attribution,
performance_by_split, early_stopping and
settings; the elements returned by 0.1.1 are kept.penalty is now
"random_effects". Pass penalty = "variance" to
reproduce results of earlier versions.performance_summary from train_gnn() has
columns Metric, Value, SD,
Lower, Upper and Splits.
Value is now the mean of the per-partition AUC (or
R-squared and RMSE), where 0.1.1 reported a single AUC pooled over all
held-out predictions.performance_summary; discrimination is summarised by AUC
(binary) or R-squared and RMSE (continuous).
analyse_gnn_results() computes the Brier score from the
held-out predictions instead, so $brier and the calibration
plot subtitle are still filled for a binary outcome.export_f360_csv() now merges gate weights onto
predictions by partition and person; previously, with repeated splits,
routing diagnostics could be attached to the wrong person.subjectid column, predictions are now
identified by the row of the supplied data rather than by their position
within a fold.