Scope
vitamin_d_status() classifies serum 25(OH)D (assumed
ng/mL) into Deficient (<20), Insufficient (20-29), or Sufficient
(>=30). It validates mappings, enforces your missing-data policy, and
can scan/cap implausible values.
When to use this
- Standardize vitamin D categorization for dashboards, cohorts, or QC summaries.
- Guard ETL steps: abort or omit rows with missing/implausible 25(OH)D before downstream models.
- Spot potential unit mix-ups: nmol/L inputs often appear ~2.5x higher than ng/mL.
Required inputs and mapping
-
data: data frame/tibble containing a 25(OH)D column. -
col_map: named list mapping eithervitdorvitamin_dto the column name. The column must exist and be coercible to numeric; coercion that introduces NAs emits a warning.
Options that change behavior
-
na_action = c("keep","omit","error","ignore","warn")(default “keep”): policy for missing 25(OH)D.warn/ignorebehave like keep;omitdrops those rows;erroraborts. -
check_extreme = FALSE: turn on plausible-range screening. -
extreme_action = c("warn","cap","error","ignore","NA")(default “warn”): response to values outside bounds. -
extreme_rules = NULL: override default bounds for vitamin D (defaults to 0 to 250 ng/mL). -
verbose = FALSE: emit progress messages.
How missingness and extremes are handled
- Missing 25(OH)D follows
na_action;omitshrinks the output;erroraborts. - Non-numeric inputs are coerced to numeric; any NAs introduced trigger a warning.
- With
check_extreme = TRUE, values outside the bounds are handled perextreme_action: warn only, cap into range, abort, ignore, or blank to NA. - Negative values and very high medians (suggesting nmol/L) warn when extreme scanning is off.
Outputs
- Tibble with ordered factor
vitamin_d_status(Deficient < Insufficient < Sufficient). - Rows drop only when
na_action = "omit"; otherwise the output aligns with input row count.
Examples
Quick categorization
library(HealthMarkers)
library(tibble)
df <- tibble::tibble(VitD = c(12, 25, 36, NA))
vitamin_d_status(
data = df,
col_map = list(vitd = "VitD"),
na_action = "keep"
)
#> # A tibble: 4 × 1
#> vitamin_d_status
#> <ord>
#> 1 Deficient
#> 2 Insufficient
#> 3 Sufficient
#> 4 NAScreen and cap extremes
df2 <- tibble::tibble(d = c(15, 280, 8, 65, NA)) # 280 is extreme by default (0-250)
vitamin_d_status(
data = df2,
col_map = list(vitd = "d"),
na_action = "warn",
check_extreme = TRUE,
extreme_action = "cap",
verbose = TRUE
)
#> # A tibble: 5 × 1
#> vitamin_d_status
#> <ord>
#> 1 Deficient
#> 2 Sufficient
#> 3 Deficient
#> 4 Sufficient
#> 5 NAVerbose diagnostics
old_opt <- options(healthmarkers.verbose = "inform")
vitamin_d_status(
data = tibble::tibble(VitD = c(15, 32)),
col_map = list(vitamin_d = "VitD"),
verbose = TRUE
)
#> vitamin_d_status(): preparing inputs
#> vitamin_d_status(): column map: vitamin_d -> 'VitD'
#> vitamin_d_status(): results: vitamin_d_status 2/2
#> # A tibble: 2 × 1
#> vitamin_d_status
#> <ord>
#> 1 Deficient
#> 2 Sufficient
options(old_opt)Troubleshooting and tips
- If medians are ~150-250 without obvious outliers, verify units (nmol/L should be divided by 2.5 to get ng/mL).
- Set
na_action = "omit"when downstream steps cannot handle NA statuses. - Tighten
extreme_rulesto your assay range, or leavecheck_extreme = FALSEwhen values are already QCed. - Keep
col_mapnamed; missing or empty mappings abort with classed errors you can assert in tests.