vignettes/articles/hormone_markers.Rmd
hormone_markers.Rmdtitle: “Hormone marker ratios” output: rmarkdown::html_vignette —
Scope
Compute nine hormone ratios with built-in QA: FAI,
LH_FSH, E2_P, T3_T4,
ARR, Ins_Glu, GH_IGF1,
PRL_T, and CAR_slope. Inputs are coerced to
numeric, non-finite become NA, and optional extreme
screening can warn, cap, blank, or error on out-of-range labs.
When to use
- You have a complete hormone panel (mapped via
col_map) and need quick ratio features. - You want explicit NA handling and optional extreme-value screening to avoid crashes on bad labs.
- You need outputs that preserve row counts unless you explicitly
omitmissing rows.
Inputs and requirements
- All keys are required: total testosterone, SHBG, LH, FSH, estradiol, progesterone, free T3, free T4, aldosterone, renin, insulin, glucagon, GH, IGF1, prolactin, cortisol_0, cortisol_30.
-
col_map: map each required key to your column names; missing mappings or columns abort. - Units: keep units consistent within each ratio (e.g., cortisol nmol/L; aldosterone/renin in matching units).
-
na_action:keep/ignoreretain rows with NA outputs;omitdrops rows with missing required inputs;erroraborts. -
check_extreme: optional;extreme_action=warn/cap/NA/error/ignore.
Load packages and demo data
Use a small synthetic tibble (covers all required inputs) so the
chunk runs anywhere. Replace horm_demo with your lab
data.
library(HealthMarkers)
library(tibble)
horm_demo <- tibble::tibble(
tt = c(5.0, 7.0, 4.5, 6.2),
shbg = c(30, 40, 28, 35),
lh = c(6, 7, 5, 6),
fsh = c(8, 9, 7, 8),
e2 = c(120, 140, 110, 135),
p4 = c(2, 3, 1.8, 2.5),
ft3 = c(4.5, 4.8, 4.3, 4.6),
ft4 = c(16, 15, 17, 16),
aldo = c(150, 120, 140, 130),
renin = c(12, 10, 11, 9),
ins = c(15, 20, 18, 17),
gluc = c(80, 70, 75, 78),
gh = c(1.2, 0.9, 1.0, 1.1),
igf1 = c(180, 160, 170, 165),
prl = c(10, 12, 11, 9),
cort0 = c(300, 280, 290, 310),
cort30 = c(480, 450, 470, 500)
)Column map (required)
Map every required key to your column names; all are mandatory for computation.
-
total_testosterone,SHBG -
LH,FSH -
estradiol,progesterone -
free_T3,free_T4 -
aldosterone,renin -
insulin,glucagon -
GH,IGF1 prolactin-
cortisol_0,cortisol_30(nmol/L; slope uses the 30-minute delta / 30)
col_map <- list(
total_testosterone = "tt",
SHBG = "shbg",
LH = "lh",
FSH = "fsh",
estradiol = "e2",
progesterone = "p4",
free_T3 = "ft3",
free_T4 = "ft4",
aldosterone = "aldo",
renin = "renin",
insulin = "ins",
glucagon = "gluc",
GH = "gh",
IGF1 = "igf1",
prolactin = "prl",
cortisol_0 = "cort0",
cortisol_30 = "cort30"
)Core calculation
Compute all ratios and preview the outputs. Non-finite values are set
to NA; rows are retained when
na_action = "keep"/"ignore".
hm_out <- hormone_markers(
data = horm_demo,
col_map = col_map,
na_action = "keep",
check_extreme = FALSE,
verbose = FALSE
)
hm_out
#> # A tibble: 4 × 10
#> FAI LH_FSH E2_P E2_T T3_T4 ARR Ins_Glu GH_IGF1 PRL_T CAR_slope
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 16.7 0.75 60 24 0.281 12.5 0.188 0.00667 2 6
#> 2 17.5 0.778 46.7 20 0.32 12 0.286 0.00562 1.71 5.67
#> 3 16.1 0.714 61.1 24.4 0.253 12.7 0.24 0.00588 2.44 6
#> 4 17.7 0.75 54 21.8 0.288 14.4 0.218 0.00667 1.45 6.33Missing data and row handling
Show the difference between keeping rows (propagating
NA) and omitting rows when required inputs are missing.
horm_demo_na <- horm_demo
horm_demo_na$ft3[2] <- NA
keep_res <- hormone_markers(
data = horm_demo_na,
col_map = col_map,
na_action = "keep",
check_extreme = FALSE
)
omit_res <- hormone_markers(
data = horm_demo_na,
col_map = col_map,
na_action = "omit",
check_extreme = FALSE
)
list(keep_rows = nrow(keep_res), omit_rows = nrow(omit_res))
#> $keep_rows
#> [1] 4
#>
#> $omit_rows
#> [1] 3Extreme screening
Enable range scanning and cap out-of-range inputs into allowed bounds.
horm_demo_ext <- horm_demo
horm_demo_ext$aldo[1] <- 2000 # intentionally extreme
cap_res <- hormone_markers(
data = horm_demo_ext,
col_map = col_map,
na_action = "keep",
check_extreme = TRUE,
extreme_action = "cap",
verbose = TRUE
)
cap_res[1, c("ARR", "FAI")]
#> # A tibble: 1 × 2
#> ARR FAI
#> <dbl> <dbl>
#> 1 83.3 16.7extreme_action = "cap" trims inputs into the allowed
ranges; warn or error emit warnings or abort
instead.
Expectations
- All required inputs must be mapped and present; missing mappings/columns abort.
-
na_action:keep/ignoreretains rows withNAoutputs;omitdrops rows with missing required inputs;errorstops on missingness. - Extreme screening is optional; when enabled, choose how to handle
flagged values with
extreme_action. - Outputs are numeric ratios; divisions by zero/non-finite are
converted to
NA.
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(
total_testosterone = 10, SHBG = 2, LH = 8, FSH = 4,
estradiol = 100, progesterone = 50, free_T3 = 5, free_T4 = 10,
aldosterone = 20, renin = 4, insulin = 20, glucagon = 10,
GH = 2, IGF1 = 4, prolactin = 12, cortisol_0 = 200, cortisol_30 = 260
)
hormone_markers(df_v,
col_map = setNames(as.list(names(df_v)), names(df_v)),
verbose = TRUE
)
#> hormone_markers(): skipping 1 ratio(s) with unmapped inputs: TSH_fT4
#> hormone_markers(): preparing inputs
#> hormone_markers(): column map: total_testosterone -> 'total_testosterone', SHBG -> 'SHBG', LH -> 'LH', FSH -> 'FSH', estradiol -> 'estradiol', progesterone -> 'progesterone', free_T3 -> 'free_T3', free_T4 -> 'free_T4', aldosterone -> 'aldosterone', renin -> 'renin', insulin -> 'insulin', glucagon -> 'glucagon', GH -> 'GH', IGF1 -> 'IGF1', prolactin -> 'prolactin', cortisol_0 -> 'cortisol_0', cortisol_30 -> 'cortisol_30'
#> hormone_markers(): results: FAI 1/1, LH_FSH 1/1, E2_P 1/1, E2_T 1/1, T3_T4 1/1, ARR 1/1, Ins_Glu 1/1, GH_IGF1 1/1, PRL_T 1/1, CAR_slope 1/1
#> # A tibble: 1 × 10
#> FAI LH_FSH E2_P E2_T T3_T4 ARR Ins_Glu GH_IGF1 PRL_T CAR_slope
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 500 2 2 10 0.5 5 2 0.5 1.2 2
options(old_opt)Tips
- Keep units consistent across rows (e.g., cortisol nmol/L, aldosterone/renin in matching units) to make ratios meaningful.
- Use
na_action = "omit"when you prefer complete-case ratios; keep/ignore if you want row counts preserved. - Tighten
extreme_rulesif your lab reference ranges are narrower than the broad defaults. - Turn on
verbose = TRUEto see coercion, missingness scan, and extreme handling summaries.