"My aggregate accuracy was ninety-four percent, which everyone celebrated. Nobody asked which six percent, so I quietly kept it all in one corner of the population."
A Diplomatically Averaged AI Agent
Prerequisites
This section assumes you can train and evaluate a subject-independent activity model, the through-line of this chapter, and understand leakage-safe subject splits from Chapter 5 and Chapter 65. Mitigation by adaptation builds on Section 26.4 (personalization); the governance framing connects to Chapter 70; and the skin-tone example draws on optical sensing physics from Chapter 30.
The Big Picture
An activity model reports one accuracy number, and that number is a population average. Averages hide their tails. A step counter that is excellent on a lab full of graduate students, young, able-bodied, moving at a brisk deliberate pace, can silently fail for a frail eighty-year-old shuffling with a walker, precisely the person a fall-risk product most needs to serve. The failure is not random noise; it is structured along the axes of body size, sex, age, gait pathology, and skin tone, because human bodies produce systematically different signals and training sets systematically over-sample some bodies over others. This section is about seeing those structured gaps, measuring them accurately instead of hiding them under an average, and closing them. Fairness in activity recognition is not a compliance checkbox bolted on at the end; it is a direct measure of whether your model works for the people who will actually wear it.
Where the gaps come from
Unfairness in human activity recognition is rarely malice and almost always physics plus sampling. Three mechanisms dominate. First, dataset composition: public benchmarks and internal collections skew toward convenient subjects, typically younger, fitter, and disproportionately male, so the model sees fewer examples of everyone else and fits them worse. Second, physiological signal differences: the same activity produces genuinely different inertial signatures across bodies. Stride length scales with leg length, so a person of height \(1.55\ \mathrm{m}\) and one of \(1.90\ \mathrm{m}\) walking at the same speed generate different step cadences and peak accelerations; a threshold tuned to the mean stride under-counts the short-legged walker. Cadence, ground-contact time, and vertical impact all shift with age, weight, footwear, and gait disorders such as Parkinsonian shuffling or a post-stroke hemiparetic swing. Third, sensor coupling: a wrist device sits and moves differently on a thin wrist than a large one, and a hip clip rides at a different angle on different body shapes, so even identical motion reaches the accelerometer transformed. The mechanism is mechanical, not statistical: a loose band lets the device rotate and translate against the limb, convolving the true motion with an uncontrolled, subject-specific transfer function the feature extractor never saw in training. The bias hits orientation-sensitive features hardest (raw axis values, tilt-derived posture), so a cheap first mitigation is preferring orientation-invariant ones such as vector magnitude and spectral energy.
A fourth mechanism is modality-specific and easy to forget in an inertial chapter: any pipeline that also ingests optical heart rate inherits the skin-tone bias of photoplethysmography. Green light is absorbed more by higher-melanin skin, lowering the pulse signal-to-noise ratio and degrading any activity or energy-expenditure estimate that leans on heart rate, an effect examined in Chapter 30. A single fairness gap can be caused by data, biomechanics, mounting, and sensor physics at once, so there is no single lever that fixes all of it.
Misconception: Deleting the Attribute Deletes the Bias
It is tempting to assume that dropping sex, age, or height from the input features makes a model fair, since it can no longer "see" the protected attribute directly. This is fairness through blindness, and it fails for physiological sensor data because the attribute is redundantly encoded in the signal itself: stride length, cadence, and impact magnitude correlate with height and age whether or not a height column ever reaches the model. Removing the explicit feature only removes your ability to audit the gap; the model can still reconstruct and exploit the correlation through the features that remain. The fix is the opposite of hiding the attribute: keep it, and use it to measure subgroup performance explicitly, as in Listing 26.6.
Key Insight
Fairness is a claim about conditional performance, not average performance, so it is invisible to any metric computed over the pooled test set. The right unit of analysis is the subgroup; the right headline number is the worst-group score, not the mean. If your model reports \(94\%\) overall while quietly delivering \(71\%\) to older women with shorter strides, its real accuracy is \(71\%\), not \(94\%\): that is the number the most vulnerable user actually experiences. Optimizing the average can actively widen the gap: gradient descent spends its capacity where the data is dense, so a lower average loss and a larger disparity often move together.
Measuring fairness without hiding the tail
Start by defining the groups explicitly. Let \(g \in \mathcal{G}\) index a protected or body-related attribute (sex, age band, height quartile, BMI band, reported mobility aid). For a per-subject or per-window accuracy \(\mathrm{acc}(g)\), two summaries matter more than the pooled mean. The gap is \(\Delta = \max_g \mathrm{acc}(g) - \min_g \mathrm{acc}(g)\), and the worst-group accuracy is \(\min_g \mathrm{acc}(g)\). For classification you usually want error-rate parity rather than raw accuracy parity, because base rates of activities differ across groups; report per-group false-negative rate on the safety-critical class (a missed fall, a missed seizure-like event) since a group with more misses is the group being failed. None of this works unless the test set is subject-split and stratified so every group is represented on the held-out side, the leakage discipline of Chapter 5 applied group by group.
The listing below computes per-group accuracy, the disparity gap, and the worst-group number from arrays of true labels, predictions, and a group tag. It is deliberately small: the audit itself should be trivial to run on every model version.
import numpy as np
def fairness_report(y_true, y_pred, groups):
y_true, y_pred, groups = map(np.asarray, (y_true, y_pred, groups))
per_group = {}
for g in np.unique(groups):
m = groups == g
per_group[g] = (y_true[m] == y_pred[m]).mean()
overall = (y_true == y_pred).mean()
worst = min(per_group.values())
gap = max(per_group.values()) - worst
return overall, worst, gap, per_group
# Toy data: majority group "M" is easy, minority "F_short" is under-served.
rng = np.random.default_rng(0)
groups = np.array(["M"] * 800 + ["F_short"] * 200)
y_true = rng.integers(0, 5, size=1000)
y_pred = y_true.copy()
flip_M = (groups == "M") & (rng.random(1000) < 0.05) # 5% error
flip_F = (groups == "F_short") & (rng.random(1000) < 0.30) # 30% error
y_pred[flip_M | flip_F] = rng.integers(0, 5, size=(flip_M | flip_F).sum())
overall, worst, gap, pg = fairness_report(y_true, y_pred, groups)
print(f"overall={overall:.3f} worst-group={worst:.3f} gap={gap:.3f}")
print({k: round(v, 3) for k, v in pg.items()})
overall accuracy looks healthy because the majority group dominates the mean, yet worst-group and gap expose that the short-stride minority is served far worse. Run this alongside your standard metrics on every model version, not once at the end.The pooled average and the worst-group number in Listing 26.6 tell different stories about the same model, and only the second one describes the user you are most likely to harm. The same skeleton extends to false-negative rate per group by swapping the accuracy line for a per-class miss rate.
The Right Tool
Rolling your own subgroup audit across several metrics, several attributes, and their intersections (sex crossed with age band) quickly balloons past 60 lines of bookkeeping. Fairlearn's MetricFrame does it in three: pass a dict of metrics, the true and predicted labels, and one or more sensitive_features, then call .by_group, .difference(), and .group_min() for the per-group table, the disparity gap, and the worst-group score, with intersectional grouping handled for free. Reach for it before hand-coding, and keep the hand-rolled version only as the on-device smoke test.
In Practice: a fall detector that missed the people it was built for
A consumer fall-detection wristband was validated on simulated falls performed by paid actors, who skewed young, athletic, and male, the demographic willing to repeatedly throw itself onto crash mats. The reported sensitivity was excellent, yet in the field, falls among the actual target population, older adults and especially older women, were detected far less reliably. The mechanism was biomechanical: a genuine geriatric fall is often a slow crumple or a slide down a wall, with lower peak acceleration and a longer, softer impact than an actor's staged tumble, so the model's impact-magnitude features, trained on the energetic young-male signature, never fired for lower-mass bodies that could not clear the acceleration threshold. The remedy combined three moves from this section: collect real-world falls across body sizes and ages, evaluate sensitivity per age-and-sex subgroup instead of pooled, and retrain to raise worst-group sensitivity rather than the average. Pooled sensitivity barely moved; worst-group sensitivity, the number that actually mattered, rose sharply.
Closing the gap
Once you can see a gap, several levers narrow it, roughly in order of cost. The cheapest is evaluation discipline: making worst-group score a first-class release gate so a regression that helps the majority but hurts a minority cannot ship unnoticed. Next is data: targeted collection to raise the density of under-served bodies, plus group-balanced or reweighted sampling so training loss stops being dominated by the majority. A principled version of reweighting is group distributionally robust optimization (Group DRO), which minimizes the loss of the worst group rather than the average, optimizing \(\min_\theta \max_{g} \mathbb{E}_{(x,y)\sim g}\,[\ell_\theta(x,y)]\), a small change to the training loop that targets \(\min_g \mathrm{acc}(g)\) directly. A complementary, powerful lever is personalization: the adaptation methods of Section 26.4 bend a general model toward the individual wearing it, dissolving many between-group gaps because a model adapted to one short-stride older user no longer needs the population to have represented her. Personalization is often the most effective fairness intervention available, since the ultimate minority group is a single person.
Two cautions apply. Mitigation can trade average for worst-group; that trade is usually right for a safety product, but state it explicitly rather than reporting only the number that improved. And fairness fixes must survive the same leakage scrutiny as everything else, and increasingly intersect with governance: many jurisdictions now expect documented subgroup performance for health-adjacent wearables, the responsible-deployment terrain of Chapter 70.
Research Frontier: Fairness Before the Fine-Tune
A growing line of work asks whether fairness can be built into the wearable foundation models of Chapter 20 before any downstream task is trained, by rebalancing the self-supervised pretraining corpus for body-size and demographic coverage rather than fixing each fine-tuned model separately. Results are mixed: a more diverse pretraining corpus narrows some worst-group gaps for free, but a representation learned from an imbalanced corpus can still encode subgroup shortcuts that fair fine-tuning fails to erase. Building group-robust objectives into pretraining itself, not only into the final fine-tune, remains an open problem.
Auditing without fooling yourself
Two failure modes turn a fairness audit into theater. The first is underpowered groups: a per-group accuracy computed on eight subjects has a confidence interval so wide that the reported gap may be pure sampling noise. Report the subject count per group and a confidence interval; a group too small to measure is itself a finding, not a clean bill of health. The second is intersectionality: a model can look fair on sex alone and on age alone yet fail specifically for older women, because the harm lives at the crossing of two axes that each look fine in isolation. Audit the intersections you have the power to measure, and treat missing intersections as unmeasured risk, not as evidence of fairness. Finally, collecting demographic labels is itself a privacy-sensitive act governed by the biometric-data constraints of Chapter 30: gather enough attribute information to detect gaps without over-collecting sensitive data, a tension to design around rather than ignore.
Exercise
Take a subject-annotated activity dataset that carries demographic metadata (for example, one with subject height, sex, and age, or construct height quartiles from reported values). Train a subject-independent classifier, then use Listing 26.6 (or Fairlearn's MetricFrame) to report overall accuracy, worst-group accuracy, and the disparity gap across height quartiles and across sex, plus the intersection of the two. Then retrain with group-balanced sampling and with a Group-DRO-style worst-group objective, and quantify how much each moves the worst-group score, the gap, and the pooled average. Report the number of subjects behind every group number and flag any group too small for a trustworthy estimate.
Self-Check
1. Why can a model that maximizes average accuracy simultaneously increase the disparity between groups? What does gradient descent "spend its capacity" on?
2. Name three distinct mechanisms that make an inertial activity model less accurate for a short, older user, and say which one data rebalancing alone cannot fix.
3. A model is fair when audited on sex alone and on age alone but fails for older women. What is this phenomenon called, and what must your audit include to catch it?
What's Next
In Section 26.7, we bring the whole chapter to bear on real deployments across fitness, healthcare, safety, and accessibility, the domains where taxonomy choices, sensor placement, segmentation, personalization, and the fairness gaps of this section stop being abstractions and start determining whether a product helps or fails the person wearing it.