The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

The problem preening() solves

Age categorisation is one of the most routine and most error-prone steps in surveillance analysis. The same dataset might need ABS 5-year bands for a national comparison, ATAGI program bands for a vaccine effectiveness study, and FluCAN bands for a sentinel surveillance report — all in the same week. preening() provides a single function backed by a catalogue of ~50 named, citable schemes so that band choice is explicit, reproducible, and traceable to a published source.

The name comes from the way a bird re-sorts its feathers into whichever functional arrangement suits the moment, without changing anything about the bird itself. The same raw age values are re-sorted into whichever standard grouping the analysis calls for.


Three ways to specify a scheme

1. Exact name

The clearest approach — name the scheme directly.

set.seed(1)
df <- data.frame(age = c(0.2, 3, 14, 25, 50, 67, 80, 92))

preening(df, age_col = "age", scheme = "atagi_covid19_2025")$age_group
#> [1] 0-<5  0-<5  5-<18 18-64 18-64 65-74 75+   75+  
#> Levels: 0-<5 < 5-<18 < 18-64 < 65-74 < 75+

2. Filter to a single match

Supply family, focus, and/or max_bands — if exactly one scheme matches, it is applied automatically and a message names it so the choice is never silent.

# vaccination + paediatric + max 3 bands → exactly one match
preening(df, age_col = "age", family = "vaccination",
         focus = "paediatric", max_bands = 3)$age_group
#> [1] 0-<6m 2y+   2y+   2y+   2y+   2y+   2y+   2y+  
#> Levels: 0-<6m < 6m-<2y < 2y+

3. Let list_age_schemes() guide you

Browse the catalogue before committing to a scheme.

list_age_schemes(family = "surveillance")
#>                     scheme       family                                 focus
#>               ed_syndromic surveillance                    surveillance|broad
#>            flucan_sentinel surveillance        surveillance|broad|national_au
#>  hospital_admitted_patient surveillance                          surveillance
#>              nndss_decadal surveillance              surveillance|national_au
#>             nndss_standard surveillance surveillance|fine_grained|national_au
#>              nors_outbreak surveillance                    surveillance|broad
#>         notifiable_std_bbv surveillance             surveillance|fine_grained
#>             racf_aged_care surveillance                surveillance|aged_care
#>  n_bands age_range
#>        6        0+
#>        5        0+
#>        6        0+
#>        9        0+
#>       10        0+
#>        5        0+
#>        6        0+
#>        5        0+

When a filter matches multiple schemes, preening() stops and lists them so you can pick one explicitly. This is intentional — preening() never guesses among ties.

# Multiple paediatric schemes exist — preening() asks you to choose
preening(df, age_col = "age", focus = "paediatric")
#> Error:
#> ! (*)> mudnester::preening() — 10 age schemes match the supplied filters (family = NULL, focus = c("paediatric"), max_bands = NULL):
#>   - unicef_child_bands
#>   - atagi_nip_schedule
#>   - pneumococcal_program
#>   - rsv_maternal_infant
#>   - neonatal_early
#>   - paediatric_developmental
#>   - school_entry_bands
#>   - who_paediatric_growth
#>   - influenza_research
#>   - rsv_research
#> Supply `scheme` explicitly to choose one, or narrow your filters further.

The scheme families

Schemes are organised into six families. Use family = to restrict your search.

Family family = value Count Examples
National statistical standards "national_stats" 10 abs_5yr, abs_broad_lifecourse
International statistical standards "international_stats" 7 who_life_course, eurostat_5yr
Vaccination/immunisation guidance "vaccination" 10 atagi_covid19_2025, flucan_sentinel
Surveillance-system conventions "surveillance" 8 nndss_standard, racf_aged_care
Clinical/developmental staging "clinical_developmental" 8 geriatric_fine, paediatric_developmental
Disease/research-specific "disease_specific" 7 rsv_research, covid19_severity_strata

Focus tags — cross-cutting filters

Every scheme carries one or more focus tags that cut across families.

list_age_schemes(focus = "aged_care")
#>                scheme                 family
#>      abs_5yr_extended         national_stats
#>      aihw_10yr_65plus         national_stats
#>       who_5yr_100plus    international_stats
#>    atagi_covid19_2025            vaccination
#>  pneumococcal_program            vaccination
#>       rsv_older_adult            vaccination
#>       shingles_zoster            vaccination
#>        racf_aged_care           surveillance
#>        geriatric_fine clinical_developmental
#>     geriatric_frailty clinical_developmental
#>   cardiovascular_risk       disease_specific
#>                                focus n_bands age_range
#>   fine_grained|national_au|aged_care      22        0+
#>                national_au|aged_care       7        0+
#>  fine_grained|who_standard|aged_care      21        0+
#>    vaccination|national_au|aged_care       5        0+
#>     vaccination|paediatric|aged_care       4        0+
#>    vaccination|aged_care|national_au       3        0+
#>                vaccination|aged_care       5        0+
#>               surveillance|aged_care       5        0+
#>               aged_care|fine_grained       7        0+
#>                      aged_care|broad       4        0+
#>             research|aged_care|broad       5        0+
# Quick summary schemes for small datasets or executive reports
list_age_schemes(focus = "broad", max_bands = 5)
#>                    scheme                 family                          focus
#>           atagi_influenza            vaccination  vaccination|national_au|broad
#>           flucan_sentinel           surveillance surveillance|broad|national_au
#>             nors_outbreak           surveillance             surveillance|broad
#>         geriatric_frailty clinical_developmental                aged_care|broad
#>        school_entry_bands clinical_developmental               paediatric|broad
#>       cardiovascular_risk       disease_specific       research|aged_care|broad
#>  mental_health_lifecourse       disease_specific                 research|broad
#>      oncology_trial_bands       disease_specific                 research|broad
#>  n_bands age_range
#>        4        0+
#>        5        0+
#>        5        0+
#>        4        0+
#>        4        0+
#>        5        0+
#>        5        0+
#>        5        0+

Neonatal schemes: age_unit = "days"

Schemes in the neonatal family use days rather than years. Pass age_unit = "days" and ensure the age column is in days.

neonates <- data.frame(age_days = c(0, 0.5, 2, 5, 15, 30))
preening(neonates, age_col = "age_days", scheme = "neonatal_early",
         age_unit = "days")$age_group
#> [1] 0-<24h  0-<24h  24-<72h 72h-<7d 7-<28d  28d+   
#> Levels: 0-<24h < 24-<72h < 72h-<7d < 7-<28d < 28d+

Custom schemes

When no standard scheme fits, supply your own breaks and labels.

preening(
  df,
  age_col    = "age",
  scheme     = "custom",
  age_breaks = c(0, 18, 40, 65, Inf),
  age_labels = c("0-17", "18-39", "40-64", "65+")
)$age_group
#> [1] 0-17  0-17  0-17  18-39 40-64 65+   65+   65+  
#> Levels: 0-17 < 18-39 < 40-64 < 65+

Catch-all bands and the full-lifespan rule

Every scheme in the mudnester library spans 0 to Inf, so preening() never returns NA purely because a record fell outside a scheme’s “intended” range. Bands marked with ⁺ in the documentation (e.g. the 0-<60 floor band in rsv_older_adult) are catch-alls — a meaningful count in one of these bands is a signal to review the scheme choice, not a finding to report.

# rsv_older_adult is scoped to 60+. A child record still gets a band.
data.frame(age = c(3, 65, 80)) |>
  preening(age_col = "age", scheme = "rsv_older_adult")
#>   age age_group
#> 1   3     0-<60
#> 2  65     60-74
#> 3  80       75+

After preening: what comes next

preening() is typically called before roost() to enable age-stratified counts:

df |>
  preening(age_col = "age", scheme = "flucan_sentinel") |>
  roost(date_col = "onset_date", time_unit = "month",
        group_cols = "age_group")

See vignette("roost") for aggregation options, and vignette("age-schemes") for the full scheme catalogue with source citations.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.