Skip to contents

Scope

Create pediatric-friendly binary risk flags (dyslipidemia, insulin resistance, hyperglycemia, hypertension) from routine labs and BP z-scores with configurable NA and extreme handling.

When to use

  • You have lipid panel, glucose/HbA1c, BP z-scores, age, and z-scored HOMA-IR and want quick binary risk features.
  • You need NA policies, high-missingness warnings, and optional extreme-value screening/capping built in.
  • You are working in pediatrics/adolescents where triglyceride thresholds differ by age and BP is already standardized.

Inputs

  • data: data.frame/tibble with required numeric inputs.
  • col_map: named list mapping required keys (defaults to same names): chol_total, chol_ldl, chol_hdl, triglycerides, age_year, z_HOMA, glucose, HbA1c, bp_sys_z, bp_dia_z.
  • Units assumed: lipids mmol/L; glucose mmol/L; HbA1c mmol/mol (IFCC); BP inputs already z-scores; age in years; z_HOMA is a z-scored HOMA-IR.
  • na_action: keep (default) propagates NA; omit drops rows missing required inputs; error aborts; ignore acts like keep; warn acts like keep plus high-missingness warnings via na_warn_prop (default 0.2).

Preparing derived inputs

Two required inputs are derived, not raw lab values:

z_HOMA (standardised HOMA-IR)

Compute HOMA-IR from fasting glucose (mmol/L) and fasting insulin (µIU/mL), then standardise to a z-score relative to a healthy reference population:

# Step 1: compute HOMA-IR
data$HOMA_IR <- (data$fasting_glucose_mmol * data$fasting_insulin_uIU) / 22.5

# Step 2: standardise within cohort (or use external reference parameters)
data$z_HOMA  <- normalize_vec(data$HOMA_IR, method = "z")

Published paediatric reference values: Keskin et al. (2005, Pediatr Diabetes); for adults, a 90th-percentile cutpoint (z ≈ 1.28) is commonly applied.

BP z-scores (bp_sys_z / bp_dia_z)

BP z-scores must be derived using sex- and age-specific normative tables (AAP 2017 Fourth Report or WHO paediatric reference). The calc_sds() function can apply stratified reference parameters if you have them; alternatively the childsds package (CRAN) provides ready-to-use paediatric normative tables.

# Manual z-score: (observed − reference_mean) / reference_sd
data$bp_sys_z <- (data$sbp - ref_sbp_mean) / ref_sbp_sd

Quick start

library(HealthMarkers)
library(tibble)

# Six children/adolescents spanning multiple metabolic risk combinations
peds <- tibble::tibble(
  chol_total    = c(5.4, 4.8, 3.9, 6.2, 5.1, 4.5),
  chol_ldl      = c(3.6, 2.9, 2.4, 4.1, 3.2, 2.8),
  chol_hdl      = c(0.9, 1.2, 1.4, 0.8, 1.0, 1.3),
  triglycerides = c(1.6, 1.0, 0.8, 2.0, 1.3, 0.9),
  age_year      = c(15,  9,  12,  17,  11,   8 ),
  z_HOMA        = c(1.5, 0.8, 0.2, 2.1, 1.0, -0.3),
  glucose       = c(5.8, 5.1, 4.9, 6.5, 5.4, 4.8),
  HbA1c         = c(40,  35,  32,  46,  38,  30 ),
  bp_sys_z      = c(1.2, 1.8, 0.3, 2.1, 0.8, -0.2),
  bp_dia_z      = c(0.5, 1.7, 0.2, 1.9, 0.6,  0.1)
)

metabolic_risk_features(
  data = peds,
  col_map = list(
    chol_total = "chol_total", chol_ldl = "chol_ldl", chol_hdl = "chol_hdl", triglycerides = "triglycerides",
    age_year = "age_year", z_HOMA = "z_HOMA", glucose = "glucose", HbA1c = "HbA1c",
    bp_sys_z = "bp_sys_z", bp_dia_z = "bp_dia_z"
  ),
  na_action = "keep"
)
#> # A tibble: 6 × 4
#>   dyslipidemia insulin_resistance hyperglycemia hypertension
#>   <fct>        <fct>              <fct>         <fct>       
#> 1 1            1                  1             0           
#> 2 0            0                  0             1           
#> 3 0            0                  0             0           
#> 4 1            1                  1             1           
#> 5 0            0                  0             0           
#> 6 0            0                  0             0

Extreme values

Extreme inputs will produce extreme or incorrect flags. Pre-filter implausible values before calling.

extreme <- peds
extreme$triglycerides[1] <- 40  # extreme; pre-filter
extreme$bp_sys_z[2] <- 9        # out of expected range; pre-filter
extreme$triglycerides[extreme$triglycerides > 30] <- NA
extreme$bp_sys_z[abs(extreme$bp_sys_z) > 5] <- NA

metabolic_risk_features(
  data = extreme,
  col_map = list(
    chol_total = "chol_total", chol_ldl = "chol_ldl", chol_hdl = "chol_hdl", triglycerides = "triglycerides",
    age_year = "age_year", z_HOMA = "z_HOMA", glucose = "glucose", HbA1c = "HbA1c",
    bp_sys_z = "bp_sys_z", bp_dia_z = "bp_dia_z"
  ),
  na_action = "warn",
  verbose = TRUE
)
#> # A tibble: 6 × 4
#>   dyslipidemia insulin_resistance hyperglycemia hypertension
#>   <fct>        <fct>              <fct>         <fct>       
#> 1 1            1                  1             0           
#> 2 0            0                  0             1           
#> 3 0            0                  0             0           
#> 4 1            1                  1             1           
#> 5 0            0                  0             0           
#> 6 0            0                  0             0

Missing data policy

missing <- peds
missing$glucose[2] <- NA

metabolic_risk_features(
  data = missing,
  col_map = list(chol_total = "chol_total", chol_ldl = "chol_ldl", chol_hdl = "chol_hdl", triglycerides = "triglycerides",
                 age_year = "age_year", z_HOMA = "z_HOMA", glucose = "glucose", HbA1c = "HbA1c",
                 bp_sys_z = "bp_sys_z", bp_dia_z = "bp_dia_z"),
  na_action = "omit"
)
#> # A tibble: 5 × 4
#>   dyslipidemia insulin_resistance hyperglycemia hypertension
#>   <fct>        <fct>              <fct>         <fct>       
#> 1 1            1                  1             0           
#> 2 0            0                  0             0           
#> 3 1            1                  1             1           
#> 4 0            0                  0             0           
#> 5 0            0                  0             0

metabolic_risk_features(
  data = missing,
  col_map = list(chol_total = "chol_total", chol_ldl = "chol_ldl", chol_hdl = "chol_hdl", triglycerides = "triglycerides",
                 age_year = "age_year", z_HOMA = "z_HOMA", glucose = "glucose", HbA1c = "HbA1c",
                 bp_sys_z = "bp_sys_z", bp_dia_z = "bp_dia_z"),
  na_action = "warn"
)
#> # A tibble: 6 × 4
#>   dyslipidemia insulin_resistance hyperglycemia hypertension
#>   <fct>        <fct>              <fct>         <fct>       
#> 1 1            1                  1             0           
#> 2 0            0                  NA            1           
#> 3 0            0                  0             0           
#> 4 1            1                  1             1           
#> 5 0            0                  0             0           
#> 6 0            0                  0             0

Expanded example: drop incomplete rows

ext_cap <- peds
ext_cap$triglycerides[1] <- 40   # extreme high
ext_cap$bp_sys_z[2] <- 9         # extreme high
ext_cap$HbA1c[2] <- NA           # missing HbA1c to trigger drop

out_cap <- metabolic_risk_features(
  data = ext_cap,
  col_map = list(
    chol_total = "chol_total", chol_ldl = "chol_ldl", chol_hdl = "chol_hdl", triglycerides = "triglycerides",
    age_year = "age_year", z_HOMA = "z_HOMA", glucose = "glucose", HbA1c = "HbA1c",
    bp_sys_z = "bp_sys_z", bp_dia_z = "bp_dia_z"
  ),
  na_action = "omit",
  verbose = TRUE
)

list(rows_returned = nrow(out_cap), flags = out_cap)
#> $rows_returned
#> [1] 5
#> 
#> $flags
#> # A tibble: 5 × 4
#>   dyslipidemia insulin_resistance hyperglycemia hypertension
#>   <fct>        <fct>              <fct>         <fct>       
#> 1 1            1                  1             0           
#> 2 0            0                  0             0           
#> 3 1            1                  1             1           
#> 4 0            0                  0             0           
#> 5 0            0                  0             0

Threshold quick-reference

Flag Logic (values in mmol/L unless noted)
Dyslipidemia CT > 5.2 OR LDL > 3.4 OR HDL < 1.0 OR TG > 1.1 (age 0–9) OR TG > 1.5 (age 10–19)
Insulin resistance z_HOMA > 1.28 (≈90th percentile)
Hyperglycemia Glucose 5.6–6.9 OR HbA1c 39–47 mmol/mol
Hypertension BP z-score > 1.64 (systolic or diastolic)

Handling and outputs

  • Missingness: keep/ignore propagate NA; omit drops rows with missing required inputs; warn logs high-missingness; error aborts on missing required inputs.
  • Outputs: tibble with factor columns dyslipidemia, insulin_resistance, hyperglycemia, hypertension (levels 0/1). Age-based TG cutoffs: >1.1 mmol/L (0–9 y) or >1.5 mmol/L (10–19 y) for dyslipidemia; BP z > 1.64 for hypertension; z_HOMA > 1.28 for insulin resistance; glucose 5.6–6.9 or HbA1c 39–47 for hyperglycemia.

Verbose diagnostics

old_opt <- options(healthmarkers.verbose = "inform")
metabolic_risk_features(
  data = peds,
  col_map = list(
    chol_total = "chol_total", chol_ldl = "chol_ldl", chol_hdl = "chol_hdl",
    triglycerides = "triglycerides", age_year = "age_year", z_HOMA = "z_HOMA",
    glucose = "glucose", HbA1c = "HbA1c", bp_sys_z = "bp_sys_z", bp_dia_z = "bp_dia_z"
  ),
  verbose = TRUE
)
#> metabolic_risk_features(): reading input 'peds' — 6 rows × 10 variables
#> metabolic_risk_features(): col_map (10 columns — 10 specified)
#>   chol_total        ->  'chol_total'
#>   chol_ldl          ->  'chol_ldl'
#>   chol_hdl          ->  'chol_hdl'
#>   triglycerides     ->  'triglycerides'
#>   age_year          ->  'age_year'
#>   z_HOMA            ->  'z_HOMA'
#>   glucose           ->  'glucose'
#>   HbA1c             ->  'HbA1c'
#>   bp_sys_z          ->  'bp_sys_z'
#>   bp_dia_z          ->  'bp_dia_z'
#> metabolic_risk_features(): computing markers:
#>   dyslipidemia       [chol_total, chol_ldl, chol_hdl, triglycerides, age_year]
#>   insulin_resistance [z_HOMA]
#>   hyperglycemia      [glucose, HbA1c]
#>   hypertension       [bp_sys_z, bp_dia_z]
#> metabolic_risk_features(): results: dyslipidemia 6/6, insulin_resistance 6/6, hyperglycemia 6/6, hypertension 6/6
#> # A tibble: 6 × 4
#>   dyslipidemia insulin_resistance hyperglycemia hypertension
#>   <fct>        <fct>              <fct>         <fct>       
#> 1 1            1                  1             0           
#> 2 0            0                  0             1           
#> 3 0            0                  0             0           
#> 4 1            1                  1             1           
#> 5 0            0                  0             0           
#> 6 0            0                  0             0
options(old_opt)

Tips

  • Keep lipids/glucose in mmol/L and HbA1c in mmol/mol; BP inputs must already be z-scores.
  • Use na_action = "omit" for analysis-ready flags; keep/warn during QA to inspect missingness.
  • Watch for HbA1c reported in % (values <=14 suggest percent) and lipids/glucose in mg/dL (would appear ~×38.7 or ×18 higher); standardize units before calling.
  • BP inputs must already be z-scores; large magnitude (|z| > 5) usually indicates scaling issues.