Scope
Compute a simplified, non-validated approximation of FRAX 10-year fracture risk (major osteoporotic and hip). Normalizes sex labels, applies HM-CS missing/extreme policies, and returns placeholder risks; it is not the proprietary FRAX algorithm.
When to use
- You need a placeholder fracture-risk proxy for demos or pipelines while acknowledging it is not clinical FRAX.
- You want explicit NA and extreme-value handling (age/BMD bounds) with column mapping flexibility.
- You plan to swap in real FRAX later; this keeps interfaces stable in the meantime.
Inputs and requirements
- Required columns (map via
col_map):age(years),sex(codes starting with m/f or 1/0). - Optional binary risk factors: prior fracture, parent fracture, glucocorticoids, rheumatoid, secondary osteoporosis, current smoker, high alcohol.
- Optional: femoral neck BMD T-score (
bmd). -
na_action:keep/ignore/warnretain rows with NA outputs;omitdrops rows missing required inputs;erroraborts. -
check_extreme: when TRUE, scan age and BMD; default bounds age 40–90, BMD T -6 to 2 (override withextreme_rules). -
extreme_action:warn(default) leaves values;captrims into bounds;NAblanks;erroraborts;ignoreskips messages.
Load packages and data
Illustrative demo data only; replace with your cohort.
library(HealthMarkers)
demo <- tibble::tibble(
Age = c(65, 72, 80, 68, 74, 60),
Sex = c("F", "M", "F", "F", "M", "F"),
prior_fx = c(1, 0, 1, 0, 0, 0),
parent_fx = c(0, 1, 0, 0, 0, 0),
steroids = c(0, 1, 0, 0, 1, 0),
rheumatoid = c(0, 0, 0, 1, 0, 0),
secondary = c(0, 0, 0, 0, 0, 0),
smoker = c(0, 1, 0, 0, 1, 0),
alcohol = c(1, 0, 0, 0, 0, 1),
bmd = c(-2.0, -1.0, -2.5, -1.5, -0.8, NA)
)Column map (required)
Provide your column names; left-hand keys are fixed.
col_map <- list(
age = "Age",
sex = "Sex",
prior_fracture = "prior_fx",
parent_fracture = "parent_fx",
steroids = "steroids",
rheumatoid = "rheumatoid",
secondary_op = "secondary",
smoker = "smoker",
alcohol = "alcohol",
bmd = "bmd"
)What each input represents
-
age: age in years (required). -
sex: sex code; first letterm/for1/0(required; normalized to male/female). - Optional binary risk factors: prior fracture, parent fracture, glucocorticoids, rheumatoid, secondary osteoporosis, current smoker, high alcohol.
-
bmd: femoral neck T-score (optional); placeholder adjustment when present.
Core calculation
Return the placeholder risks and the normalized age/sex/BMD used.
frax_out <- frax_score(
data = demo,
col_map = col_map,
na_action = "keep",
check_extreme = TRUE,
extreme_action = "warn",
verbose = FALSE
)
head(dplyr::select(frax_out, frax_major_percent, frax_hip_percent, frax_sex_norm, frax_age_used, frax_bmd_tscore))
#> # A tibble: 6 × 5
#> frax_major_percent frax_hip_percent frax_sex_norm frax_age_used
#> <dbl> <dbl> <chr> <dbl>
#> 1 15.5 8.5 female 65
#> 2 14.4 8.9 male 72
#> 3 19 13.3 female 80
#> 4 10.4 6 female 68
#> 5 11.8 7.6 male 74
#> 6 7 3.5 female 60
#> # ℹ 1 more variable: frax_bmd_tscore <dbl>Interpretation: frax_major_percent and
frax_hip_percent are placeholder probabilities (not
clinical). frax_sex_norm shows normalized sex;
frax_age_used and frax_bmd_tscore reflect any
capping/blanking applied by extreme checks.
Inputs and reminders
- Required:
age(years) andsexcodes mapped incol_map. - Optional: binary risk factors and BMD T-score. Non-numeric inputs are coerced; non-finite values become NA.
-
na_action:keep/ignore/warnretain rows with NA outputs;omitdrops rows missing required inputs;erroraborts. -
check_extreme: when TRUE, scan age and BMD; defaults bounds age 40–90, BMD T -6 to 2 (override withextreme_rules). -
extreme_action:warn(default) leaves values;captrims into bounds;NAblanks;erroraborts;ignoreskips messages.
Missing data and extremes
Show row handling, capping, and dropping on a small slice.
demo_miss <- demo
demo_miss$Age[3] <- NA # missing age
demo_miss$Sex[4] <- "X" # unknown sex -> NA
demo_miss$Age[5] <- 105 # extreme age
demo_miss$bmd[2] <- -7 # extreme BMD
keep_cap <- frax_score(
data = demo_miss,
col_map = col_map,
na_action = "keep",
check_extreme = TRUE,
extreme_action = "cap",
verbose = FALSE
)
omit_cap <- frax_score(
data = demo_miss,
col_map = col_map,
na_action = "omit",
check_extreme = TRUE,
extreme_action = "cap",
verbose = FALSE
)
list(
keep_rows = nrow(keep_cap),
omit_rows = nrow(omit_cap),
capped_preview = head(dplyr::select(keep_cap, frax_age_used, frax_bmd_tscore, frax_major_percent, frax_hip_percent))
)
#> $keep_rows
#> [1] 6
#>
#> $omit_rows
#> [1] 4
#>
#> $capped_preview
#> # A tibble: 6 × 4
#> frax_age_used frax_bmd_tscore frax_major_percent frax_hip_percent
#> <dbl> <dbl> <dbl> <dbl>
#> 1 65 -2 15.5 8.5
#> 2 72 -6 14.4 8.9
#> 3 NA -2.5 NA NA
#> 4 68 -1.5 NA NA
#> 5 90 -0.8 15 12
#> 6 60 NA 7 3.5Here na_action = "keep" retains rows even with
missing/unknown sex or age (outputs become NA).
na_action = "omit" drops rows missing required inputs.
extreme_action = "cap" trims age/BMD into allowed ranges
before risk calculation.
Expectations
- Placeholder approximation only; not a validated FRAX calculator and not for clinical use.
- You must map
ageandsex; missing mappings or columns abort. - Choose
na_actionto enforce or relax completeness;erroris strict,omitdrops,keepretains. - Use
check_extreme/extreme_actionto cap, blank, or reject out-of-range age/BMD (defaults age 40–90, BMD T -6 to 2). -
verbose = TRUEsurfaces progress and QA messages.
Verbose diagnostics
Set verbose = TRUE (and
healthmarkers.verbose = "inform") to surface three
structured messages on each call: preparing inputs, the column map, and
a results summary.
old_opt <- options(healthmarkers.verbose = "inform")
df_v <- data.frame(Age = c(65, 72), Sex = c("F", "M"),
bmd = c(-2.0, -1.0))
frax_score(
df_v,
col_map = list(age = "Age", sex = "Sex", bmd = "bmd"),
verbose = TRUE
)
#> frax_score(): preparing inputs
#> frax_score(): column map: age -> 'Age', sex -> 'Sex'
#> frax_score(): results: frax_major_percent 2/2, frax_hip_percent 2/2, frax_sex_norm 2/2, frax_age_used 2/2, frax_bmd_tscore 2/2
#> # A tibble: 2 × 5
#> frax_major_percent frax_hip_percent frax_sex_norm frax_age_used
#> <dbl> <dbl> <chr> <dbl>
#> 1 8.5 4.7 female 65
#> 2 5.4 3.3 male 72
#> # ℹ 1 more variable: frax_bmd_tscore <dbl>
options(old_opt)Tips
- Normalize sex coding to
M/For 1/0 before calling to avoid NA normalization. - Adjust
extreme_rulesif your bounds differ; setcheck_extreme = FALSEto skip scanning. - Use
na_action = "error"for strict pipelines;omitto filter incomplete rows;keep/warnfor exploratory use. - Outputs are illustrative only; replace with a validated FRAX implementation for clinical workflows.