| Title: | Reproducible Cardiovascular Health Metric Scoring |
| Version: | 0.9.0 |
| Description: | Provides a reproducible R implementation of the American Heart Association Life's Essential 8 cardiovascular health scoring framework for adults aged 20 years or older and children aged 4 months to 19 years. Calculates the eight component scores and their unweighted composite score from available component data, including raw MEPA, DASH, and HEI-2015 diet inputs and pediatric growth-chart and blood-pressure percentiles, using the 2022 definitions described by Lloyd-Jones et al. (2022) <doi:10.1161/CIR.0000000000001078>. |
| License: | MIT + file LICENSE |
| Depends: | R (≥ 4.1.0) |
| Encoding: | UTF-8 |
| Language: | en-US |
| Imports: | cli (≥ 3.6.0), generics, rlang (≥ 1.1.0) |
| Suggests: | cdcanthro, dplyr (≥ 1.1.0), ggforestplotR (≥ 0.6.0), ggplot2 (≥ 3.4.0), knitr, mice (≥ 3.16.0), pedbp, rmarkdown, testthat (≥ 3.0.0), tibble |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| Config/Needs/website: | pkgdown |
| Config/Needs/build: | digest, haven, survey |
| URL: | https://thatoneguy006.github.io/essential8/, https://github.com/thatoneguy006/essential8 |
| BugReports: | https://github.com/thatoneguy006/essential8/issues |
| Config/roxygen2/version: | 8.1.1 |
| NeedsCompilation: | no |
| Packaged: | 2026-11-14 20:56:20 UTC; Carso |
| Author: | Carson Richardson |
| Maintainer: | Carson Richardson <carson.richardson@outlook.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-11-14 21:20:09 UTC |
essential8: Reproducible cardiovascular health metric scoring
Description
essential8 is a transparent, versioned, and auditable implementation of
published adult cardiovascular health metric definitions. Adult scoring,
including transparent handling of unavailable components, is based on the
American Heart Association's 2022 Life's Essential 8 definition and is
available through score_le8().
Scientific status
The adult scoring rules in version 0.3.0 are implemented from the cited AHA, DASH, and HEI-2015 sources and covered by boundary and input-validation tests. Users remain responsible for verifying measurement protocols, population-specific diet cutpoints or percentiles, and caller-adjudicated clinical-judgment flags. The package is research software and is not intended for clinical decision support.
Author(s)
Maintainer: Carson Richardson carson.richardson@outlook.com (ORCID) [copyright holder]
Authors:
Carson Richardson carson.richardson@outlook.com (ORCID) [copyright holder]
Other contributors:
Amrik Khalsa Amrik.Khalsa@nationwidechildrens.org (ORCID) [contributor]
Sara Conroy (ORCID) [contributor]
See Also
Useful links:
Report bugs at https://github.com/thatoneguy006/essential8/issues
Add pediatric growth-chart and blood-pressure reference values
Description
Derives the reference inputs that score_le8() needs for pediatric BMI and
blood-pressure scoring from raw measurements:
-
bmi_percentileandbmi_percent_of_p95(ages 2 to 19): CDC 2000 BMI-for-age percentile, using the CDC extended BMI method above the 95th percentile, and BMI as a percentage of the 95th percentile, fromcdcanthro::cdc_z(). -
infant_weight_zandinfant_weight_percentile(under age 2): WHO weight-for-length (or BMI-for-age) z-score and percentile, fromcdcanthro::who_z(). -
systolic_bp_p90,systolic_bp_p95,diastolic_bp_p90, anddiastolic_bp_p95(ages 1 to 12): the AAP 2017 (Flynn et al.) 90th and 95th blood-pressure percentiles for the child's age, sex, and height, frompedbp::q_bp().
Requires the suggested packages cdcanthro (for growth charts) and
pedbp (for blood pressure); each is needed only when data contains
rows of the corresponding ages. Values are left missing outside the stated
ages and wherever a required measurement is missing. In particular, the
blood-pressure references are not computed without height: pedbp
would otherwise assume a median-height child.
infant_weight_z_change, the change in the infant z-score since the prior
routine visit, needs longitudinal data and is not derived here. Compute it
from infant_weight_z within each child; see
vignette("pediatric-scoring").
Usage
add_pediatric_references(
data,
sex = "sex",
height = "height_cm",
weight = "weight_kg",
bmi = NULL,
age_months = NULL,
completed_months = FALSE,
infant_measure = c("weight_for_length", "bmi_for_age"),
bp_source = "flynn2017"
)
Arguments
data |
A data frame. Rows aged 20 or older are returned unchanged. |
sex |
Name of the sex column: |
height |
Name of the column holding height in cm (recumbent length before age 2). |
weight |
Name of the column holding weight in kg. |
bmi |
Optional name of a BMI column in kg/m^2. When |
age_months |
Optional name of a column holding age in months. When
|
completed_months |
If |
infant_measure |
Under age 2, |
bp_source |
The pedbp blood-pressure reference. The default,
|
Value
data, with the eight reference columns described above appended.
It is an error for data to contain any of them already.
References
Lloyd-Jones DM, Allen NB, Anderson CAM, et al. (2022). Life's Essential 8. Circulation, 146(5), e18-e43. doi:10.1161/CIR.0000000000001078
Flynn JT, Kaelber DC, Baker-Smith CM, et al. (2017). Clinical Practice Guideline for Screening and Management of High Blood Pressure in Children and Adolescents. Pediatrics, 140(3), e20171904. doi:10.1542/peds.2017-1904
Wei R, Ogden CL, Parsons VL, Freedman DS, Hales CM (2020). A method for calculating BMI z-scores and percentiles above the 95th percentile of the CDC growth charts. Annals of Human Biology, 47(6), 514-521. doi:10.1080/03014460.2020.1808065
See Also
Examples
children <- data.frame(
id = c("a", "b"),
age = c(5.5, 14),
sex = c("female", "male"),
height_cm = c(112, 165),
weight_kg = c(19, 70)
)
add_pediatric_references(children)
Restore LE8 score methods to a data frame
Description
score_le8() returns an essential8_scores object: the input data frame
(or tibble), with its original class, plus the score columns. The extra
class provides summary(),
tidy(), plot(), and,
with dplyr loaded, summarise().
Row-wise operations such as filter(), mutate(), arrange(), joins, and
bind_rows() keep the class. group_by(), summarise() with
expressions, as_tibble(), pivot_longer(), and saving to and reading from
a file drop it. as_le8_scores() adds the class back to any data frame that
still contains the score columns. It does not rescore or change any values.
A data frame with an .imp column, such as saved results from
score_le8_imputed(), becomes an essential8_imputed_scores object, so
its methods pool across imputations again.
Usage
as_le8_scores(x)
Arguments
x |
A data frame containing the columns returned by |
Value
x, with the class essential8_scores added, and
essential8_imputed_scores too when x has an .imp column.
See Also
Examples
scores <- score_le8(
data.frame(age = 45, sleep_hours = 7.5, bmi = 24, bmi_profile = "general"),
min_components = 2
)
plain <- as.data.frame(scores)
summary(as_le8_scores(plain))
Construct a reference for population diet scoring
Description
Creates a small, method-specific reference for DASH or HEI-2015 indices,
including HEI-2015 totals calculated from raw inputs. Raw DASH with custom
definitions requires explicit dash_cutpoints in score_le8() to specify
intake quintiles as well. The four values are index-score cutpoints at the indicated
percentiles, not percentiles themselves. No observations are stored or ranked.
Usage
diet_reference(
p25,
p50,
p75,
p95,
method = "dash",
label = NULL,
source = NULL,
score_range = NULL
)
Arguments
p25, p50, p75, p95 |
Single finite numeric cutpoints, in nondecreasing order. |
method |
Either |
label, source |
Optional single nonempty strings describing the reference population and its source. These do not change scoring. |
score_range |
Optional numeric vector of two finite bounds identifying the index's theoretical range. HEI-2015 always uses 0 to 100. DASH has multiple definitions, so a custom DASH reference has no implicit range. |
Value
An essential8_diet_reference object containing the method,
cutpoints, optional metadata, and index range. It identifies percentile
bands, not an exact continuous percentile distribution.
Examples
ref <- diet_reference(40, 55, 65, 80, method = "hei2015",
label = "Synthetic example")
ref
Options for imputing missing LE8 inputs
Description
Sets how score_le8() imputes missing inputs when impute is used. Pass
the result as score_le8(impute = le8_imputation_control(...));
impute = TRUE uses the defaults.
Usage
le8_imputation_control(m = 20, maxit = 5, seed = NA, auxiliary = NULL, ...)
Arguments
m |
Number of imputed data sets, at least 2. A common rule of thumb for final analyses is at least as many imputations as the percentage of participants with any missing input. |
maxit |
Number of mice iterations. |
seed |
A whole number to make the imputations reproducible, or |
auxiliary |
Optional character vector of other complete columns to use
as predictors, such as analysis outcomes, exposures, or survey design
variables; see |
... |
Further arguments to |
Value
An essential8_imputation_control object.
See Also
score_le8(), le8_imputation_setup()
Examples
le8_imputation_control(m = 50, seed = 2026)
Prepare LE8 inputs for multiple imputation with mice
Description
le8_imputation_setup() returns the settings mice::mice() needs to
multiply impute missing score_le8() inputs in a way the AHA scoring rules
can use. score_le8(impute = TRUE) uses them to impute and score in one
call; call le8_imputation_setup() yourself to inspect the settings, or to
adjust them and run mice directly, then score the result with
score_le8_imputed().
Imputing the inputs, rather than the 0-100 scores, keeps the relationships between measurements that the AHA bands then summarize. The setup encodes what is specific to LE8:
-
Only inputs a person's age uses are imputed. For example, adult BMI is never imputed for a child, nor blood-pressure percentile thresholds for an adult, nor a MEPA item that a preschooler's screener does not include. Observed values in such structurally unused cells are set to
NAin the prepared data so they cannot distort the imputation models.years_since_quitis imputed only for adults who are, or may be imputed as, former smokers. -
Predictors are limited to inputs available (observed or imputed) for everyone the target applies to, plus
ageand anyauxiliarycolumns, so no model relies on structurally missing values. -
Methods: predictive mean matching (
"pmm") for numeric inputs, which imputes only observed values and so respects their range and skew; logistic regression ("logreg") for two-level inputs; and multinomial regression ("polyreg") otherwise. Logical and character inputs are converted to factors for mice;score_le8_imputed()converts them back. -
Combinations AHA does not score are never imputed. Diagnosed diabetes implies an HbA1c measure. Current combustible smoking is never paired with current inhaled-NDS use. An observed fasting glucose implies no diagnosed diabetes, and an observed HbA1c of 6.5% or more implies diagnosed diabetes. Each imputed glucose value comes from donors with the same measure and diabetes status, and a measure is imputed only if such donors exist. These rules run in mice's
poststep of every iteration, so the other imputation models condition on consistent values.
Two values that follow from observed data are filled in before imputation
(deductive imputation): glucose_measure is "hba1c" when diabetes is
TRUE, and current_inhaled_nds is FALSE for current smokers.
Usage
le8_imputation_setup(data, auxiliary = NULL, diet_method = "mepa")
Arguments
data |
A data frame of |
auxiliary |
Optional character vector of other columns in |
diet_method |
The diet scoring method; only |
Details
Observed values are validated with score_le8() first, so data that cannot
be scored stop here rather than after imputation. Every observed
glucose_value needs its glucose_measure.
Only the MEPA diet screener is supported. Inputs must use the default
column names, and age must be complete.
With adults and children in one data set, inputs that apply to only one
population cannot predict inputs that apply to both. To use richer models,
impute each population separately and combine the results with
rbind(), which mice provides for mids objects.
Imputation models should include the variables used in later analyses,
such as exposures and outcomes. Pass them in auxiliary.
score_le8(impute = TRUE) calls mice::mice() with
remove.collinear = FALSE and remove.constant = FALSE. mice's defaults
would stop imputing an input that is constant or collinear in the observed
data, leaving values that scoring needs missing. Each imputation model still
drops such predictors on its own. When calling mice::mice() directly with
a setup, pass the same two arguments.
Glucose values mix units (mg/dL for fasting glucose, % for HbA1c), so
glucose_measure and glucose_value predict only each other; diabetes
represents glucose status in the other models.
Value
An essential8_imputation_setup object, a list with the prepared
data and the mice arguments method, predictorMatrix, where,
visitSequence, and post, plus inputs, a data frame describing each
input: the rows it applies to, the values to impute, and the method.
See Also
score_le8() and its impute argument to impute and score in one
call; le8_imputation_control(); score_le8_imputed() to score your own
mice run.
Examples
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
adults$non_hdl_cholesterol[c(2, 5)] <- NA
adults$sleep_hours[3] <- NA
setup <- le8_imputation_setup(adults)
setup
# Adjust the settings, then run mice yourself: here, sleep hours are no
# longer predicted from age. Keep predictive mean matching for numeric
# inputs; methods such as "norm" can impute values outside their valid
# range, which score_le8() then rejects.
setup$predictorMatrix["sleep_hours", "age"] <- 0
imputed <- mice::mice(
setup$data,
m = 5,
method = setup$method,
predictorMatrix = setup$predictorMatrix,
where = setup$where,
visitSequence = setup$visitSequence,
post = setup$post,
remove.collinear = FALSE,
remove.constant = FALSE,
seed = 1,
printFlag = FALSE
)
summary(score_le8_imputed(imputed))
Plot LE8 scores
Description
Draws the scores returned by score_le8() with ggplot2:
-
"components"(the default): the mean composite and component scores. With a single row, these are that person's scores. -
"distribution": box plots of the composite and component scores. -
"composite": a histogram of the composite score, filled by cardiovascular health category. -
"forest": a forest plot of the mean composite and component scores with confidence intervals, optionally compared across the groups inby, drawn byggforestplotR::ggforestplot(). Requires the ggforestplotR package.
Dashed lines mark the moderate (50) and high (80) thresholds. Missing scores are left out. The result is a ggplot object, so it can be modified with further ggplot2 layers, scales, and themes. For other designs, start from tidy().
Usage
## S3 method for class 'essential8_scores'
plot(
x,
type = c("components", "distribution", "composite", "forest"),
by = NULL,
...
)
Arguments
x |
An |
type |
The plot to draw: |
by |
For |
... |
For |
Value
A ggplot object.
Forest plots
For type = "forest", each row is a measure: the mean score and its
t-based confidence interval, from the rows with that score available.
Measures with fewer than two available scores in a group have no interval
and are left out. With by, rows with a missing group are left out, and
groups are ordered by factor level (or sorted, for other columns).
Imputed scores
For scores from score_le8_imputed(), "components" shows pooled means
and "forest" pooled means with Rubin's-rules confidence intervals.
"distribution" shows the stacked imputed data sets, and "composite"
weights each row by 1/m so the bars count participants.
Arguments in ... are passed to ggforestplotR::ggforestplot(), so its
styling options work as usual, for example striped_rows = TRUE,
point_size, dodge_width, ref_line, or sort_terms. conf.level
(default 0.95) sets the interval level as well as the label. The data
mapping arguments (data, term, estimate, conf.low, conf.high,
label, group, and n) are set by plot(). Composition helpers such as
ggforestplotR::add_forest_table() can be added to the result.
See Also
tidy.essential8_scores(), summary.essential8_scores()
Examples
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
scores <- score_le8(adults)
plot(scores)
plot(scores, type = "distribution")
plot(scores, type = "composite")
# Compare groups in a forest plot, passing styling to ggforestplotR.
plot(scores, type = "forest", by = "bmi_profile", striped_rows = TRUE)
Objects exported from other packages
Description
These objects are imported from other packages. Follow the links below to see their documentation.
- generics
Score Life's Essential 8 cardiovascular health
Description
Computes the eight Life's Essential 8 (LE8) component scores and the composite score using the American Heart Association's 2022 Presidential Advisory. Rows aged 20 years or older are scored with the adult definitions; rows aged 4 months to 19 years are scored with the pediatric definitions. Component scores are calculated wherever sufficient inputs are available, without imputing missing values.
Usage
score_le8(
data,
diet_method = "mepa",
mepa_columns = NULL,
min_components = 7L,
dash_columns = NULL,
dash_cutpoints = NULL,
hei2015_columns = NULL,
hei2015_cutpoints = NULL,
reference = "nhanes_2015_2018",
impute = FALSE
)
Arguments
data |
A data frame with one row per person (or visit) and the input columns described below. Adults and children may be mixed. |
diet_method |
A single diet-scoring method applied to every row in
|
mepa_columns |
|
min_components |
A single integer from 1 to 8 specifying the minimum
number of non-missing LE8 component scores required to calculate
|
dash_columns, hei2015_columns |
|
dash_cutpoints |
|
hei2015_cutpoints |
|
reference |
|
impute |
Whether to multiply impute missing inputs before scoring:
|
Value
An essential8_scores object: data, with its original class (so tibbles
and grouped tibbles are returned as such) and columns, plus
mepa_total (items met on the age-appropriate MEPA screener: 0-16 from
age 6, 0-10 at ages 2-5, 0-6 at 6-23 months), dash_total, and
hei2015_total (missing unless calculated from the corresponding raw
inputs), physical_activity_moderate_equivalent_minutes (weekly minutes
used for adults and children aged 6+), the eight component scores
(diet_score, physical_activity_score, nicotine_score, sleep_score,
bmi_score, blood_lipids_score, blood_glucose_score, and
blood_pressure_score), n_components, le8_composite_score,
le8_complete, le8_category, and le8_population ("adult" or
"pediatric"). The component count reports how many
scores contributed to the composite score; le8_complete is TRUE
only when all eight components are available. Categories are "low" for
scores below 50, "moderate" for scores from 50 to less than 80, and
"high" for scores of at least 80. The category is missing when the
composite score is missing.
For raw DASH calls, the eight component scores (1 to 5 points each) are
also appended as dash_<field>_score; they sum to dash_total.
For raw HEI-2015 calls, the 13 component scores are also appended as
hei2015_<component>_score, including fatty_acids and saturated_fats.
With impute, an essential8_imputed_scores object instead: the scored
completed data sets stacked, with the imputation number in .imp and the
row of data in .id. It is a data frame, or a tibble for tibble input
(ungrouped). The mids object from mice is kept as attr(x, "mids") for
diagnostics, for example plot(attr(x, "mids")) to check convergence.
data must not already contain any of these output columns (compared
case-insensitively), or the le8_-prefixed component names used by
essential8 0.3.0 and earlier; rename or remove them first.
The essential8_scores class adds summary(),
tidy(), plot(), and
dplyr summarise() methods. See
as_le8_scores() for when the class is kept and how to restore it.
Diet scoring methods
MEPA retains the individual assessment pathway. For population research,
diet_method = "dash" accepts an already-computed index in dash, and
diet_method = "hei2015" accepts an already-computed index in hei2015.
Either method alternatively accepts a percentile in diet_value (0 to 100).
Both methods also calculate raw totals from the intake fields below, using
the packaged reference by default. Raw HEI-2015 also accepts a custom
diet_reference(); raw DASH supports custom definitions via dash_cutpoints.
Do not supply both the index column and an observed percentile; an
entirely missing diet_value column is ignored. Data with no diet inputs
retain the package's usual missing-component behavior. Once raw scoring is
selected, every raw input column must be present (values may be missing);
an absent column is an error rather than a silently missing diet score.
An index is compared with fixed reference cutpoints to identify its
percentile category. The package does not estimate an exact percentile
from four cutpoints, or rank the current cohort against itself. Specify
reference = "nhanes_2015_2018" explicitly in reproducible analyses.
The built-in DASH reference is specifically the 8-to-40 Fung-style FPED
construction identified as essential8_fung_fped_v1; it requires matching
food definitions, pooled weighted intake quintiles, and tie handling.
Other DASH definitions need a custom reference. HEI-2015 indices must be
constructed using an appropriate established method; the built-in reference
uses individual scoring after averaging the same two recalls' constituents
and energy. It is not a usual-intake or population-ratio estimate. Both
references use NHANES 2015-2016 and 2017-2018, two-day dietary weights divided
by two, and the NHANES strata and PSU design. Detailed methodology, source
URLs, hashes, sample counts, and index definitions accompany the references
and the maintainer script data-raw/build_diet_references.R in the repository.
Fractional inputs confined to 0-1 (other than endpoints alone) are rejected as apparent proportions; supply percentile points, such as 95, not 0.95. This safeguard also rejects a batch consisting only of genuine fractional percentiles below 1. Values are never automatically multiplied by 100.
Supply one input pathway per call: raw intake, a precomputed index, or a
percentile. Raw intake fields cannot be combined with a precomputed index
or observed percentile. Raw fields are food-group and nutrient summaries,
prepared before scoring; the function does not parse dietary-recall files.
See vignette("population-diets") for executable examples and units.
Input columns
The column names below are case-sensitive; a name that differs only by
case (for example BMI) is an error. MEPA, DASH, and HEI-2015 diet fields
are matched case-insensitively. A column whose values are all missing may
be logical NA (as read.csv() produces for a blank column). Columns that
only apply to adults or only to children are ignored for other rows.
-
age: Age in years; must be present, complete, and at least 4 months (1/3 year). Rows aged 20 or older are scored as adults. -
age_months: Optional age in months, used for the pediatric age bands when observed. It must fall within the same completed year asage. For
diet_method = "mepa", the 16 Table C screener-item columns named below andsex(orfemalewhensexis absent). The same columns serve children; see Pediatric input columns for which items each age uses. The item names are matched exactly after case normalization. If any screener item is present, every field used at the ages indatais required (all 16 items and sex when any row is aged 6 or older); omitting every item leaves the diet component missing. Supply daily servings inolive_oil,green_leafy_vegetables,other_vegetables, andwhole_grains; supply weekly servings or frequency inberries,other_fruit,meat,fish,chicken,cheese,butter_cream,beans,sweets_and_pastries,nuts, andalcohol; supply the number of times per week that fast-food meals are consumed infast_food. Sex may be encoded as"m"/"f","male"/"female", or0/1, where0is male and1is female. Character encodings are matched case-insensitively, and character"0"/"1"values are also accepted. A logicalfemalecolumn (TRUEfor female) is also accepted.-
dashorhei2015: An already-computed index for the selected population diet method. HEI-2015 is bounded by 0 to 100. The built-in DASH reference requires its documented 8-to-40 definition; custom DASH references can specify other index ranges. These columns are unrelated to MEPA. For raw DASH scoring, supply daily intakes in
dash_fruits,dash_vegetables,dash_nuts_and_legumes,dash_whole_grains,dash_low_fat_dairy,dash_red_and_processed_meat, anddash_sweetened_beverages; supply sodium in mg/day indash_sodium. Canonical mapping fields omit thedash_prefix. Fruits include juice; vegetables exclude potatoes and legumes. Food groups and serving definitions must match the reference. With the packaged reference, also supply positive kcal/day indash_energy_kcal; sodium is standardized to 2,000 kcal before scoring. Other fields must use the FPED-derived units and definitions invignette("population-diets"), including fruit cup equivalents, whole-grain ounce equivalents, and the specified vegetable, dairy, protein, and beverage conversions. With explicitdash_cutpoints, energy is not required and no standardization is applied.For raw HEI-2015 scoring, supply
hei2015_energy_kcal(positive kcal/day, including alcohol); cup equivalents/day inhei2015_total_fruits,hei2015_whole_fruits,hei2015_total_vegetables,hei2015_greens_and_beans, andhei2015_dairy; ounce equivalents/day inhei2015_whole_grains,hei2015_total_protein_foods,hei2015_seafood_and_plant_proteins, andhei2015_refined_grains; grams/day inhei2015_polyunsaturated_fat,hei2015_monounsaturated_fat, andhei2015_saturated_fat; mg/day inhei2015_sodium; and teaspoon equivalents/day inhei2015_added_sugars. Canonical mapping fields omit thehei2015_prefix. Food-group totals must already include legumes in both vegetable and protein components as specified by HEI-2015. Total fruits include juice; whole fruits do not.-
diet_value: A direct percentile for"dash","hei2015", or the backward-compatible generic"percentile"method. Supply a DASH or HEI-2015 percentile from 0 to 100, calculated against the relevant reference distribution. The function does not rank supplied rows against one another. If this column is absent or missing, the diet score is missing. MEPA and raw-intake calls require it to be absent or entirely missing. -
moderate_activity_minutesandvigorous_activity_minutes: Weekly minutes. For adults, each vigorous minute counts as two moderate-equivalent minutes; for children aged 6 to 19, every minute counts once. -
smoking_status: One of"never","former", or"current". See Pediatric input columns for the pediatric meaning. -
years_since_quit: Years since quitting combustible tobacco. This is used only for adults whosesmoking_statusis"former". -
current_inhaled_nds: Whether an inhaled nicotine-delivery system is currently used. -
secondhand_smoke_home: Whether the person lives with an active indoor smoker. -
sleep_hours: Average hours of sleep per night (per 24 hours, including naps, for children aged 5 or younger). -
bmi: Adult body mass index in kg/m^2. Values below 18.5 are not scored because the AHA advisory defers to clinician judgment for underweight adults. -
bmi_profile: Either"general"or"asian_pacific"(adults). The function never infers a profile from race or ethnicity. -
non_hdl_cholesterol: Non-HDL cholesterol in mg/dL. -
lipid_lowering_treatment: Whether the lipid value is drug treated. -
diabetes: Whether diabetes has been diagnosed. -
glucose_measure: Either"fasting_glucose"or"hba1c". -
glucose_value: Fasting glucose in mg/dL or HbA1c in percent, as named byglucose_measure. Diagnosed diabetes requires HbA1c. A record with no diabetes diagnosis but a value in the diagnostic diabetes range is rejected because the AHA scoring table does not assign that combination. -
systolic_bpanddiastolic_bp: Blood pressure in mm Hg. -
antihypertensive_treatment: Whether the blood pressure is treated.
Component input columns may contain missing values or be omitted. A
component score is NA_real_ when its available inputs are insufficient.
Missing values are never imputed. A warning is emitted when an entire LE8
component cannot be calculated for any observation where AHA defines it.
Pediatric scoring
Rows aged 4 months to 19 years use the children column of Table 1 of the advisory and the suggested rules for younger children in its Supplemental Appendix 2:
Diet: MEPA (the adult 16-item screener and adult bands at ages 6-19; a 10-item subset at 10 points per item at ages 2-5; a 6-item subset at ages 6-23 months), or population percentiles at ages 2-19. Not scored before 6 months.
Physical activity: daily active play at ages 1-5; weekly moderate or vigorous minutes at ages 6-19. Not scored before 1 year.
Nicotine exposure, sleep, BMI, blood lipids, and blood glucose: all pediatric ages, with age-appropriate sleep ranges, growth-chart BMI (weight-for-length or BMI percentile before age 2), and pediatric non-HDL cholesterol bands. Glucose uses the adult table.
Blood pressure: AAP 2017 percentile categories at ages 1-12, adult bands at ages 13-19. Not scored before 1 year.
Components AHA does not define at a row's age are NA and are not counted
toward min_components; a message notes any such inputs that were
supplied. AHA recommends averaging the components that are available and
appropriate for measurement in children (the NHANES analysis averaged as few
as three), so pediatric analyses usually set a lower min_components.
add_pediatric_references() can derive the growth-chart and
blood-pressure reference inputs. See vignette("pediatric-scoring").
Where the sources conflict, the package follows the more specific rule: the supplement's 2-5 year diet rule (10 points per item) rather than the Table 1 bands; and, for 6-23 month weight, the supplement's explicit 0-point worst state (at or above the 99.7th percentile with rapid gain) rather than its decrements, which would leave 25. Nineteen-year-olds use the 13-18 year sleep range (8 to 10 hours), the last range AHA lists.
Pediatric input columns
-
smoking_status:"never"(never tried any nicotine product),"former"(tried a nicotine product, but not within 30 days), or"current"(combustible use within 30 days).current_inhaled_ndsis inhaled-NDS use within 30 days and caps the score at 25. Record"never"andFALSEfor young children without exposure;secondhand_smoke_homeapplies at every age. -
active_play_minutes: Ages 1-5. Average daily minutes of active play of any intensity over 7 days. -
bmi_percentileandbmi_percent_of_p95: Ages 2-19. CDC BMI-for-age percentile (0-100) and BMI as a percentage of the 95th percentile (for example, 125). The latter is used only at or above the 95th percentile. Percentiles below the 5th are rejected because AHA defers to clinician judgment. -
infant_weight_percentileandinfant_weight_z_change: Under age 2. WHO weight-for-length (or BMI-for-age) percentile, and the increase in the matching z-score since the prior routine visit (for example, since age 1 month). The change is required from 6 months; 0.67 or more counts as rapid weight gain. -
systolic_bp_p90,systolic_bp_p95,diastolic_bp_p90, anddiastolic_bp_p95: Ages 1-12. The child's AAP 2017 90th and 95th blood-pressure percentiles in mm Hg for age, sex, and height. MEPA, ages 2-5: ten of the adult items. Vegetables are
green_leafy_vegetables + other_vegetables(at least 2 per day) and fruit isberries + other_fruit(at least 14 per week, i.e. 2 per day);whole_grains(3+ per day),olive_oil(1+ per day),fish(1+ per week),nuts(4+ per week),meat(3 or fewer per week),butter_cream(3 or fewer per week),sweets_and_pastries(3 or fewer per week), andfast_food(2 or fewer per month, i.e. at most 24/52 per week). For children under 6,sweets_and_pastriesshould include sugar-sweetened beverages.MEPA, ages 6-23 months: vegetables and fruit as above (at least 1 per day before 12 months, 2 per day from 12 months),
whole_grains(same thresholds), no sweets or sugar-sweetened beverages, no fast food, andmilk_source:"human","cow","formula", or"other". Human milk meets the item before 12 months; human or cow's milk from 12 months.
Optional clinical-judgment columns
-
apply_lean_muscular_bmi_override: A caller-adjudicated flag asserting that a lean, higher-muscle-mass adult in the general BMI profile has a BMI from 25 to less than 30 and should receive 100 BMI points. If absent, the standard BMI band is used. Not defined for children. -
apply_sleep_apnea_penalty: IfTRUE, subtract 20 points for untreated or undertreated sleep apnea (adults or children). If absent, no discretionary penalty is applied. -
apply_prediabetes_metformin_penalty: A caller-adjudicated flag asserting that the person has a history of prediabetes, is taking metformin to prevent diabetes, is currently normoglycemic, and the clinician chose to apply the AHA's discretionary 20-point decrement. If absent, no discretionary penalty is applied.
Source-constrained behavior
The function derives the 0-to-16 MEPA total from the 16 raw screener
responses. Raw DASH scoring uses the eight-component Fung index: five food
groups receive 1 to 5 points by intake quintile; sodium, red/processed meat,
and sweetened beverages receive 5 to 1. Intakes equal to a quintile cutpoint
stay in the lower quintile. Their sum is dash_total (8 to 40).
Raw HEI-2015 calls compute 13 density, fatty-acid-ratio, and energy-percentage
components with proportional scoring between the published standards.
Added sugars use 16 kcal per teaspoon equivalent; saturated fat uses
9 kcal per gram. Scores are capped at each component's maximum. Their sum
is hei2015_total (0 to 100), which is distinct from the LE8 diet score.
With zero saturated fat and positive unsaturated fat, the fatty-acid
component receives 10 points; with all three fats zero it receives zero,
following the NCI scoring macro. Missing inputs are never treated as zero;
a total requires all of its diet components, regardless of min_components.
Raw DASH and HEI-2015 totals are converted to LE8 scores of 0, 25, 50, 80,
or 100 using fixed reference total-score cutpoints. Equality enters the
higher LE8 band. Explicit cutpoints override the packaged reference and
must come from a suitable fixed reference population, using appropriate
survey weights and strata where applicable. Cutpoints are never inferred
from data. For references requiring
different cutpoints by stratum, score strata in separate calls. Alternatively,
diet_method = "percentile" accepts externally calculated DASH or HEI-2015
percentiles. The rows in data are never ranked against one another.
The AHA table applies 20-point treatment decrements to blood-lipid and blood-pressure scores. These components are floored at zero, consistent with the AHA's 0-to-100 metric definition. Optional sleep-apnea and prediabetes/metformin decrements are applied only through explicit flags. Inputs are not rounded. The documented MEPA daily/weekly equivalences are applied where the source question and criterion use different timeframes. Combinations without a source-defined score, including simultaneous current combustible smoking and current inhaled-NDS use, produce a structured error.
Input errors inherit from essential8_input_error and essential8_error.
General and adult errors also carry essential8_adult_input_error, as in
earlier versions; pediatric-only errors carry
essential8_pediatric_input_error.
Multiple imputation
With impute, score_le8() fills in missing inputs with mice::mice()
several times, scores every completed data set, and returns them stacked.
The imputation:
checks the observed values, so data that cannot be scored stop before imputation;
imputes an input only for participants whose age uses it (adult BMI is never imputed for a child, for example), predicting it from age, the other inputs available for the same participants, and any
auxiliarycolumns;uses predictive mean matching for numeric inputs, so imputed values are always values observed in someone else, and logistic or multinomial regression for categorical inputs;
never imputes a combination the AHA scoring rules do not score, such as diagnosed diabetes without an HbA1c, current smoking with current inhaled-NDS use, or a fasting glucose of 126 mg/dL or more without diagnosed diabetes.
min_components then applies to each completed data set as usual.
summary(), dplyr
summarise(), and plot() pool
the results across imputations with Rubin's rules. See
le8_imputation_setup() for the full rules, and to inspect or adjust them.
Imputation assumes values are missing at random given the variables in the
imputation models; include the variables used in later analyses, such as
exposures and outcomes, with le8_imputation_control(auxiliary = ).
References
Lloyd-Jones DM, Allen NB, Anderson CAM, et al. (2022). Life's Essential 8: Updating and Enhancing the American Heart Association's Construct of Cardiovascular Health. Circulation, 146(5), e18-e43. doi:10.1161/CIR.0000000000001078
Lloyd-Jones DM, Ning H, Labarthe D, et al. (2022). Status of Cardiovascular Health in US Adults and Children Using the American Heart Association's New Life's Essential 8 Metrics. Circulation, 146(11), 822-835. doi:10.1161/CIRCULATIONAHA.122.060911
Flynn JT, Kaelber DC, Baker-Smith CM, et al. (2017). Clinical Practice Guideline for Screening and Management of High Blood Pressure in Children and Adolescents. Pediatrics, 140(3), e20171904. doi:10.1542/peds.2017-1904
Fung TT, Chiuve SE, McCullough ML, et al. (2008). Adherence to a DASH-Style Diet and Risk of Coronary Heart Disease and Stroke in Women. Archives of Internal Medicine, 168(7), 713-720. doi:10.1001/archinte.168.7.713
Krebs-Smith SM, Pannucci TE, Subar AF, et al. (2018). Update of the Healthy Eating Index: HEI-2015. Journal of the Academy of Nutrition and Dietetics, 118(9), 1591-1602. doi:10.1016/j.jand.2018.05.021 See also the National Cancer Institute's scoring standards and algorithm.
See Also
summary.essential8_scores(), tidy.essential8_scores(), and
plot.essential8_scores() to summarize, reshape, and plot the scores;
add_pediatric_references() to derive pediatric growth-chart and
blood-pressure inputs; diet_reference() for custom diet references.
Examples
library(dplyr)
patient <- tibble(
id = "patient_1",
age = 55,
sex = "female",
# Daily servings
olive_oil = 2,
green_leafy_vegetables = 1,
other_vegetables = 2,
whole_grains = 2,
# Weekly servings
berries = 3,
other_fruit = 5,
meat = 2,
fish = 3,
chicken = 2,
cheese = 1,
butter_cream = 1,
beans = 3,
sweets_and_pastries = 1,
nuts = 4,
alcohol = 4,
# Fast-food meals per week
fast_food = 0,
moderate_activity_minutes = 90,
vigorous_activity_minutes = 0,
smoking_status = "former",
years_since_quit = 6,
current_inhaled_nds = FALSE,
secondhand_smoke_home = FALSE,
sleep_hours = 7.5,
bmi = 27.5,
bmi_profile = "general",
non_hdl_cholesterol = 145,
lipid_lowering_treatment = FALSE,
diabetes = FALSE,
glucose_measure = "fasting_glucose",
glucose_value = 95,
systolic_bp = 128,
diastolic_bp = 78,
antihypertensive_treatment = FALSE
)
scores <- score_le8(patient, diet_method = "mepa")
select(scores, id, mepa_total, diet_score, le8_composite_score,
le8_category)
# A 4-year-old with the preschool diet screener and no laboratory values.
child <- tibble(
id = "child_1",
age = 4,
# Ten MEPA items apply at ages 2-5; sweets include sugary drinks.
green_leafy_vegetables = 1, other_vegetables = 1, # servings per day
berries = 7, other_fruit = 14, # servings per week
whole_grains = 2, olive_oil = 1, # servings per day
sweets_and_pastries = 2, meat = 2, fish = 1, # servings per week
nuts = 2, butter_cream = 1,
fast_food = 0.25, # times per week
active_play_minutes = 160,
smoking_status = "never", current_inhaled_nds = FALSE,
secondhand_smoke_home = FALSE,
sleep_hours = 11,
bmi_percentile = 60, bmi_percent_of_p95 = 85,
systolic_bp = 98, diastolic_bp = 58,
systolic_bp_p90 = 103, systolic_bp_p95 = 107,
diastolic_bp_p90 = 63, diastolic_bp_p95 = 67,
antihypertensive_treatment = FALSE
)
child_scores <- score_le8(child, min_components = 5)
select(child_scores, id, mepa_total, ends_with("_score"), n_components)
# Multiply impute missing inputs, then pool the scores.
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
adults$non_hdl_cholesterol[c(2, 5)] <- NA
imputed <- score_le8(adults, impute = le8_imputation_control(m = 5, seed = 1))
summary(imputed)
Score multiply imputed LE8 inputs
Description
Scores every completed data set from a multiple imputation and returns
them stacked, with the imputation number in .imp. Methods for the result
pool across imputations with Rubin's rules: summary() and, with dplyr,
summarise() report pooled means with confidence intervals, and
plot(type = "forest") draws pooled intervals.
Usage
score_le8_imputed(data, ...)
Arguments
data |
A |
... |
Arguments passed to |
Value
An essential8_imputed_scores object: the stacked scored data sets,
a subclass of essential8_scores. Its summary(), summarise(),
tidy(), and plot() methods account for the imputations.
Pooling
Each statistic is estimated in every imputed data set and combined with
Rubin's rules. Means are pooled with total variance
T = \bar{U} + (1 + 1/m) B and Barnard-Rubin degrees of freedom; the
fraction of missing information (fmi) describes how much the
imputations add to the uncertainty. Category percentages are pooled the
same way. Standard deviations and quantiles are averaged across
imputations, which describes the distribution but carries no interval.
See Also
Examples
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
adults$non_hdl_cholesterol[c(2, 5)] <- NA
# Stacked completed data sets, as any imputation software might return.
completed <- function(imp, value) {
out <- adults
out$non_hdl_cholesterol[is.na(out$non_hdl_cholesterol)] <- value
cbind(.imp = imp, out)
}
stacked <- rbind(completed(1L, 150), completed(2L, 170))
summary(score_le8_imputed(stacked))
Summarise multiply imputed LE8 scores with dplyr
Description
The summarise() method for scores from
score_le8_imputed(). Without expressions, it returns the pooled
statistics in summary(), one row per
measure and group. With expressions, it is ordinary dplyr on the stacked
data sets; add .imp to .by to summarise each imputation separately.
Usage
## S3 method for class 'essential8_imputed_scores'
summarise(.data, ..., .by = NULL, .groups = NULL)
Arguments
.data |
An |
... |
Summary expressions. If any are supplied, the call is handled by
|
.by |
< |
.groups |
Passed to |
Value
Without expressions, an ungrouped data frame with the grouping
columns, measure, and the pooled statistics: n, n_missing, mean,
std.error, conf.low, conf.high (95%), df, fmi, and the averaged
sd, min, q25, median, q75, and max. With expressions, the
result of dplyr::summarise().
See Also
summary.essential8_imputed_scores()
Summarise LE8 scores with dplyr
Description
With dplyr loaded, calling summarise() (or summarize()) on scores from
score_le8() without any summary expressions returns the statistics in
summary() as a data frame, one row per
measure and group. Calls with expressions, such as
summarise(scores, mean = mean(le8_composite_score)), are passed to
dplyr unchanged.
Groups come from .by, or from the grouping of a grouped tibble passed to
score_le8(). Because group_by() drops the essential8_scores class,
use .by for grouped summaries of scored data, or restore the class with
as_le8_scores().
Usage
## S3 method for class 'essential8_scores'
summarise(.data, ..., .by = NULL, .groups = NULL)
Arguments
.data |
An |
... |
Summary expressions. If any are supplied, the call is handled by
|
.by |
< |
.groups |
Passed to |
Value
Without expressions, an ungrouped data frame of the same type as
.data (a tibble for tibble input) with the grouping columns, measure
(a factor: composite, then the eight components in AHA order), and the
statistics n (available scores), n_missing, mean, sd, min,
q25, median, q75, and max. With expressions, the result of
dplyr::summarise().
See Also
summary.essential8_scores(), tidy.essential8_scores()
Examples
library(dplyr)
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
scores <- adults |>
select(!starts_with("expected_")) |>
score_le8()
summarise(scores)
summarise(scores, .by = bmi_profile)
# Ordinary dplyr summaries work as usual.
summarise(scores, mean_le8 = mean(le8_composite_score), .by = bmi_profile)
Summarize multiply imputed LE8 scores
Description
Pools the scores from score_le8(impute = TRUE) or score_le8_imputed()
across imputations with
Rubin's rules. Means and category percentages get pooled confidence
intervals and the fraction of missing information; standard deviations
and quantiles are averaged across imputations. Counts are per participant
(averaged across imputations), not per stacked row.
Usage
## S3 method for class 'essential8_imputed_scores'
summary(object, conf_level = 0.95, ...)
## S3 method for class 'summary.essential8_imputed_scores'
print(x, digits = 1, ...)
Arguments
object |
An |
conf_level |
Confidence level for the pooled intervals. |
... |
Not used. |
x |
A |
digits |
Number of decimal places to print. |
Value
summary() returns a summary.essential8_imputed_scores object, a
list with n (participants), m (imputations), population,
n_composite, n_complete, statistics (one row per measure with n,
n_missing, pooled mean, std.error, conf.low, conf.high, df,
and fmi, and averaged sd, min, q25, median, q75, and max),
categories (pooled percentages with confidence intervals),
conf_level, and settings. print() returns x invisibly.
See Also
score_le8_imputed(), summary.essential8_scores()
Examples
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
adults$non_hdl_cholesterol[c(2, 5)] <- NA
scores <- score_le8(
adults,
impute = le8_imputation_control(m = 5, seed = 1)
)
summary(scores)
summary(scores)$statistics
Summarize LE8 scores
Description
Summarizes the composite and component scores returned by score_le8():
how many rows were scored, the distribution of each score, and the
cardiovascular health categories. Grouping is ignored; use
summarise() for summaries by group.
Usage
## S3 method for class 'essential8_scores'
summary(object, ...)
## S3 method for class 'summary.essential8_scores'
print(x, digits = 1, ...)
Arguments
object |
An |
... |
Not used. |
x |
A |
digits |
Number of decimal places to print. |
Value
summary() returns a summary.essential8_scores object, a list
with:
-
n: the number of rows. -
population: the number of adult and pediatric rows. -
n_composite: rows with a composite score. -
n_complete: rows with all eight component scores. -
statistics: a data frame with one row per measure (the composite and each component) and the columnsmeasure,n(available scores),n_missing,mean,sd,min,q25,median,q75, andmax. -
categories: a data frame with the count and percentage of rows in each category among rows with a composite score. -
settings: thediet_methodandmin_componentsused for scoring, orNULLwhen unknown (for example, afteras_le8_scores(), or after dplyr verbs on a plain data frame, which drop custom attributes).
print() returns x invisibly.
See Also
tidy.essential8_scores(), summarise.essential8_scores(),
plot.essential8_scores()
Examples
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
scores <- score_le8(adults)
summary(scores)
# The statistics are also available as a data frame.
summary(scores)$statistics
Tidy LE8 scores into long format
Description
Reshapes the composite and component scores returned by score_le8() into
long format, with one row per input row and measure. This is the shape
ggplot2 and grouped summaries expect.
Usage
## S3 method for class 'essential8_scores'
tidy(x, id_cols = NULL, composite = TRUE, ...)
Arguments
x |
An |
id_cols |
Optional character vector of columns in |
composite |
Whether to include the composite score as a measure. |
... |
Not used. |
Value
A data frame of the same type as x (a tibble for tibble input),
ungrouped, with the columns:
-
row: the row ofxthe score comes from. the
id_cols.-
le8_population:"adult"or"pediatric". -
measure: a factor;composite(when included), thendiet,physical_activity,nicotine,sleep,bmi,blood_lipids,blood_glucose, andblood_pressure. -
score: the score, from 0 to 100, orNAwhen unavailable.
See Also
summary.essential8_scores(), plot.essential8_scores()
Examples
adults <- read.csv(system.file(
"extdata", "le8-adult-example.csv", package = "essential8"
))
adults <- adults[!startsWith(names(adults), "expected_")]
scores <- score_le8(adults)
head(tidy(scores, id_cols = "id"), 9)