| Title: | Standardized Metrics Based on the CDC and WHO Growth Charts |
| Version: | 0.5.0 |
| Date: | 2026-10-30 |
| Description: | Calculation of sex- and age-standardized growth metrics using the LMS method (lambda-mu-sigma). The package includes functions for the CDC Growth Charts (cdc_z) and the WHO Charts (who_z). Because CDC recommends using the WHO Charts for children under 24 months and the CDC Charts among older children, there can be large differences at age 2.0 years. For example, a girl weighing 9.9 kg would be at the WHO 10th percentile on the day before her second birthday, but at the CDC 2nd percentile the following day. The 'gradual_z' function reduces the differences among 2- to 5-year-olds by taking a weighted average of the CDC and WHO z-scores. |
| License: | GPL-3 |
| Encoding: | UTF-8 |
| LazyData: | true |
| ByteCompile: | true |
| NeedsCompilation: | no |
| Depends: | R (≥ 3.5.0) |
| Imports: | data.table (≥ 1.15.0), stats, utils |
| Suggests: | tibble, callr, testthat (≥ 3.1.5) |
| Config/testthat/edition: | 3 |
| Packaged: | 2026-10-30 14:40:54 UTC; davidfreedman |
| Author: | David Freedman |
| Maintainer: | David Freedman <DavidSFreedman@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-10-30 18:10:02 UTC |
cdcanthro: Sex- and Age-Standardized Metrics from the CDC and WHO Growth Charts
Description
Calculation of sex- and age-standardized growth metrics using the LMS method (lambda-mu-sigma). The function cdc_z(), previously named cdcanthro(), uses the 2000 CDC growth charts for children and adolescents with ages of >= 24.0 to < 240 months, to generate sex- and age-standardized z-scores and percentiles for weight, height, and body mass index (BMI). The output includes extended BMI z-scores for values above the 95th percentile to more accurately characterize children with very high BMIs.
Because CDC recommends the WHO Growth Standards for children under 2 years of age, there is also a function, who_z(), which computes sex- and age- (or length-) standardized metrics for children under five years of age.
There is also a function, gradual_z(), which smooths the discontinuities at age 2.0 resulting, in large part, from the use of different reference data. For example, a girl weighing 9.9 kg would be at the 10th percentile the day before her second birthday and at the 2nd percentile the following day.
Author(s)
David S Freedman
Maintainer: David S Freedman <DavidSFreedman@gmail.com>
Other contributors:
Carrie Daymont cdaymont@pennstatehealth.psu.edu [contributor]
Sample Anthropometric Data from NHANES
Description
A sample dataset of 7393 NHANES participants. Variables include height, weight, sex, and age in months. Note that months is given as the completed number of months.
Usage
data(NHanes)
Format
A data frame or data table with observations on multiple anthropometric variables.
CDC Growth Chart Reference Data (2000)
Description
LMS parameters (L, M, S) for age- and sex-standardized growth metrics.
Usage
data(cdc_ref_data)
Format
A data.table with columns for sex, age, and LMS values. Parameter names represent the first letter of weight, height, or BMI; this is followed by 'l', 'm', or 's' for the LMS parameters. 'mref' and 'sref' are the M and S parameters for BMI at 240 months of age. For sexn, '1' = boys and '2' = girls.
Source
https://www.cdc.gov/growthcharts/percentile_data_files.htm https://www.cdc.gov/growthcharts/extended-bmi-data-files.htm
Generate Sex- and Age-Standardized Weight, Height, and BMI Metrics From the CDC Growth Charts
Description
Generate z-scores, percentiles, and other sex- and age-standardized metrics
for weight, height, and BMI based on the 2000 CDC growth charts. For children with obesity,
the extended BMI z-scores and percentiles are calculated. The calculations are restricted
to children with ages between 24.0 (inclusive) and < 240 months. For younger children, use who_z.
Note that cdc_z is the preferred name; the previous name, cdcanthro, will work but is deprecated.
The BMI metrics include z-scores and percentiles, along with newer metrics such as extended BMIz and percent of the 50th and 95th percentiles. The extended BMI metrics are used for BMIs above the 95th percentile.
Usage
cdc_z(data, age = agemos, wt = wt, ht = ht, bmi = bmi,
sex_code = 1:2, all_vars = FALSE)
cdcanthro(data, age = agemos, wt = wt, ht = ht, bmi = bmi,
sex_code = 1:2, all_vars = FALSE)
Arguments
data |
a |
age |
Age in months, specified as accurately as possible. Required. |
wt |
Weight in kg. Optional. If omitted, WAZ-related metrics will be missing. |
ht |
Height in cm. Optional. If omitted, HAZ-related metrics will be missing. |
bmi |
BMI in |
sex_code |
Numeric, single-digit coding for sex if other than 1 for boys and 2 for girls. Optional. |
all_vars |
logical. If |
Details
Argument values can be quoted (e.g., age='agemos') or unquoted (age = agemos).
The function expects the child's sex to be named sex; either upper- or
lower-case is fine. You cannot have both SEX and sex in your data.
Values can be coded as boys/girls, b/g, male/female,
m/f, or 1/2. Character values can be upper- or lower-case, and
only the first character is considered. Be aware that a code of 'missing' will be interpreted
as a boy.
If sex is numeric and not coded as 1/2, specify this in the optional sex_code argument;
the code for boys is the first number. For example, 0/1 coding would be specified as
sex_code = 0:1 or sex_code = c(0,1).
Weight is in kg, height is in cm, and BMI is in kg/m^2.
At least one of wt, ht, or bmi must be present. Metrics that cannot be
calculated from the supplied variables are silently omitted from the output. If a supplied
column name doesn't exist in data (a likely typo), a warning is issued.
Age in months should be given as accurately as possible because the function
linearly interpolates between completed months of age. If ages are given as the
completed number of months (as in NHANES), add 0.5 because values such as 36 represent the
interval [36, 37) months. If the function detects integer numbers for all ages, it
will add 0.5 to all age values during the calculations; the input ages are not changed.
If age is in days, divide by 30.4375 so that a child who is 3672 days old would have an age in months of 120.641. For additional information on age, see the ‘See Also’ section below.
If all_vars = TRUE, all variables in the Freedman et al. paper will be
output, along with the L, M, and S values for each child and the value of
sigma for the half-normal distribution.
For children without obesity, BMI z-scores are calculated as
Z = ((BMI / M)^L - 1) / (L \times S)
where BMI is the child's BMI, L is the Box-Cox transformation
for normality for the child's sex and age, M is the median, and
S is the coefficient of variation. Reference data are the merged
LMS files from the CDC (see ‘See Also’).
For children with obesity, BMI percentiles are calculated as
90 + 10 \times \Phi((\mathrm{BMI} - \mathrm{p95}) / \sigma)
where p95 is the sex- and age-specific 95th percentile, \Phi is the
CDF of a N(0, 1) distribution (pnorm()), and sigma is the scale parameter
of the half-normal distribution. Values of sigma for children with obesity
are based on formulas in Wei et al.
The class of the returned object matches the class of the input data:
a data.frame input returns a data.frame, a data.table
returns a data.table, and a tibble (tbl_df) returns a tibble
(provided the tibble package is installed; otherwise a
data.frame is returned with a warning).
Value
A data.table, data.frame, or tibble containing the original
data and various weight, height, and BMI metrics.
If your dataset has ages that are < 24 or >= 240 months, these rows will be present in the output
dataset. All calculated metrics will be NA. If this is not what you want, delete these rows before
running cdc_z().
Variables in output:
waz,haz,bmizSex- and age-standardized z-scores for weight, height, and BMI.
bmizis based on the 2000 CDC growth charts for non-obese children and extended BMIz for obese children.wap,hap,bmipSex- and age-standardized percentiles for weight, height, and BMI.
bmipis based on the extended BMI metrics for obese children.mod_waz,mod_haz,mod_bmizModified z-scores used to flag outliers; see the CDC SAS program.
orig_bmip,orig_bmizOriginal BMI percentiles and z-scores based solely on the LMS method.
orig_bmizandbmizare identical for BMIs at or below the 95th percentile.p95The 95th percentile for BMI in the reference data for each sex and age.
bmip95BMI expressed as a percentage of the 95th percentile; 120 percent is the lower threshold for severe obesity.
perc_medianPercent difference between the child's BMI and the median (50th percentile) BMI for the child's sex and age.
If all_vars = TRUE, additional BMI metrics described in Freedman et al.
are also returned. These express BMI as distance or percent distance from
the median. To convert to percent of the median, add 100 to the values.
Note
Argument names can be quoted or unquoted: cdc_z(data, age, wt, ht, bmi),
and cdc_z(data, 'age', 'wt', 'ht', 'bmi') produce the same result.
Author(s)
David Freedman DavidSFreedman@gmail.com
References
Kuczmarski RJ, Ogden CL, Guo SS, Grummer-Strawn LM, Flegal KM, Mei Z, et al. 2000 CDC Growth Charts for the United States: methods and development. Vital and Health Statistics Series 11, Data from the National Health Survey 2002;11:1–190.
Wei R, Ogden CL, Parsons VL, Freedman DS, Hales CM. A method for calculating BMI z-scores and percentiles above the 95th percentile of the CDC growth charts. Annals of Human Biology 2020;47(6):514–521. doi:10.1080/03014460.2020.1808065
Freedman DS, Woo JG, Ogden CL, Xu JH, Cole TJ. Distance and Percent Distance from Median BMI as Alternatives to BMI z-score. British Journal of Nutrition 2019;124:1–8.
See Also
who_z for standardized values for children < age 2.0 y based on the WHO charts
CDC LMS percentile data files: https://www.cdc.gov/growthcharts/percentile_data_files.htm
CDC extended BMI data files: https://www.cdc.gov/growthcharts/extended-bmi-data-files.htm
CDC SAS programs and more information on agemos in Table 1 of
https://www.cdc.gov/growth-chart-training/hcp/computer-programs/sas.html
Examples
data <- data.table::CJ(sex = 1:2, agem = 120.5, wtk = c(30, 65), htc = c(135, 144))
data[, let(bmi = wtk / (htc / 100)^2)]
out <- cdc_z(data, age = agem, wt = wtk, ht = htc, bmi = bmi)
round(out, 2)[1:5]
out <- cdc_z(data, age = agem, wt = wtk, ht = htc, bmi = bmi, all_vars = TRUE)
round(out, 2)[1:5]
d <- data.frame(sex = c(1, 2, 1, 2, 2),
age = c(141, 54, 217, 155, 52),
wt = c(57, 25, 72, NA, 17.7),
ht = c(143, 102, 166, 169, 105))
d <- cdc_z(d, age, wt, ht)
round(d, 2)
d <- data.frame(sex = c(0, 1, 0),
age = c(120.5, 60.5, 180.5),
wt = c(40, 25, 65))
cdc_z(d, age, wt, sex_code = 0:1) # note use of sex_code
# tibble input returns a tibble (requires the tibble package)
if (requireNamespace("tibble", quietly = TRUE)) {
d_tbl <- tibble::as_tibble(d)
cdc_z(d_tbl, age, wt, sex_code = 0:1)
}
head(NHanes) # age is given as completed months
d <- data.table::copy(NHanes)
head(cdc_z(d, agemos, wt, ht, bmi))[,.(seqn, agemos, waz, haz, bmiz)]
d[, let(agemos = agemos + 0.5)]
head(cdc_z(d, agemos, wt, ht, bmi))[,.(seqn, agemos, waz, haz, bmiz)]
# same Z-scores
Gradual WHO-to-CDC Transition Z-Scores
Description
Computes a smooth, gradually transitioning z-score for weight, height/length, and body mass index (BMI) that blends World Health Organization (WHO) and Centers for Disease Control and Prevention (CDC) growth reference z-scores across early childhood. These gradual z-scores use WHO z-scores up to 730 days (2.0 y) of age, CDC z-scores are used from 1826 days (5.0 y) of age onward, and a weighted average of the CDC and WHO z-scores between ages 2 and 5 years.
Gradual z-scores avoid the abrupt jump produced by switching directly from WHO to CDC
references at age 2 years as recommended by CDC. For example, under an abrupt
switch, a girl weighing 9.9 kg would be at the 10th percentile (WHO) the day
before her second birthday and at the 2nd percentile (CDC) the following day;
gradual_z avoids this discontinuity.
Usage
gradual_z(data,
agedays = agedays,
whowtz = who_waz,
cdcwtz = waz,
whohtz = who_lhaz,
cdchtz = haz,
whobmiz = who_bmiz,
cdcbmiz = bmiz)
Arguments
data |
A |
agedays |
Column for age in days. Note that all arguments can be either unquoted or quoted. |
whowtz |
WHO weight-for-age z-score. |
cdcwtz |
CDC weight-for-age z-score. |
whohtz |
WHO length/height-for-age z-score. |
cdchtz |
CDC height-for-age z-score. |
whobmiz |
WHO BMI-for-age z-score. |
cdcbmiz |
CDC BMI-for-age z-score. |
Details
Naming the arguments rather than relying on position is recommended.
However, if the input was created using cdc_z and
who_z, the function can be called as gradual_z(data). Argument values
can be quoted or unquoted.
For each row, age in days determines which of three regions applies:
-
agedays
\le730 (through 2 years): the WHO z-score is used directly. -
730 < agedays < 1826 (2 to 5 years): a weighted average of the WHO and CDC z-scores is used, with weights that shift linearly with age so the blended value equals the WHO z-score at 730 days and the CDC z-score at 1826 days.
-
agedays
\ge1826 (5 years and beyond): the CDC z-score is used directly.
This produces a transition that is continuous at both boundaries, avoiding
the discontinuity that would result from switching abruptly from WHO to CDC
references at a single cutoff age. Note that if data already contains
grad_waz, grad_haz, or grad_bmiz, the column is overwritten
and a warning() is issued.
For ages between 2 and 5 years, the gradual z-score is a weighted average of the WHO and CDC z-scores:
Z_{gradual} = \frac{Z_{WHO} \times (5 - \mathrm{ageyears}) + Z_{CDC} \times (\mathrm{ageyears} - 2)}{3}
It should be noted that gradual z-scores from 2 through 5 years of age are not directly comparable to those based on other reference data, and researchers may need sensitivity analyses to facilitate comparison with other studies.
Further, because of the change in recumbent length to standing height at age 2.0 years, a discontinuity at this age will be present for grad_haz and grad_bmiz.
Value
An object of the same class as data (data.frame,
data.table, or tibble), containing all columns of data, plus:
grad_waz |
Gradual (blended) weight-for-age z-score. Added only if both
|
grad_haz |
Gradual (blended) height/length-for-age z-score. Added only if
both |
grad_bmiz |
Gradual (blended) BMI-for-age z-score. Added only if both
|
Each of the three gradual measures is checked independently. If neither column of a
pair is found, that measure is skipped with an informational message().
If only one column of a pair is found, that measure is skipped with a warning() instead.
If no complete pair is found, a warning() is issued.
In the output, each measure's columns are grouped together in the order WHO, CDC, and
gradual (e.g. who_waz, waz, grad_waz), for weight,
then height, then BMI; any other input columns (including agedays) come first.
Author(s)
David Freedman DavidSFreedman@gmail.com
References
Daymont C, Hwang W, Paul IM, Shur N, Freedman DS (2025). "Creation and Evaluation of New Growth Charts With a Gradual Transition From WHO to CDC Values." Pediatrics, 156(3), e2025070697. doi:10.1542/peds.2025-070697
See Also
The original growth charts, tables, and R/Stata code are available at https://github.com/carriedaymont/gradual-who-cdc.
Examples
library(data.table)
dt <- data.table(
agedays = c(730, 1096, 1461, 1826), # 2, 3, 4, and 5 years of age
who_waz = c(0.9, 0.7, 0.6, 0.4),
waz = c(0.7, 0.5, 0.3, 0.3),
who_lhaz = c(-0.2, 0.1, 0.2, 0.1),
haz = c(-0.3, 0.0, 0.1, 0.2),
who_bmiz = c(1.0, 0.9, 0.8, 0.7),
bmiz = c(0.1, 0.5, 0.2, 0.2)
)
result <- gradual_z(dt, agedays, who_waz, waz, who_lhaz, haz, who_bmiz, bmiz)
result[, ageyears:= round(agedays/365.25,2)]
result
gradual_z(dt) # because column names match defaults
WHO Reference Data
Description
LMS parameters (L, M, S) in the WHO charts for age- and sex-standardized growth metrics.
Usage
data(who_ref_data)
Format
A data.table with columns for sex (sexn coded as 1 (boys) / 2 (girls)), age in days, and LMS values. Variable names represent the weight (wei), length or height (len), BMI (bmi), weight-for-length (wfl), or head circumference (headc). This prefix is followed by '_' and then by 'l', 'm', or 's' representing the LMS parameters.
Sexn is coded as '1' (boys) and '2' (girls).
In contrast to the sex- and age-standardized metrics, weight-for-length is weight standardized for sex and length; it represents the distribution of weights for a specific length. Note that the length/height reference values are given in 0.01 cm increments.
The 'denom' variable indicates if the row represents age-standardization or len-standardization.
Source
https://www.who.int/toolkits/child-growth-standards/standards
Sex- and Age- (or Length-) Standardized Weight, Length/Height, BMI, and Head Circumference Metrics from the WHO Growth Charts
Description
Calculates z-scores and biologically-implausible-value (BIV) flags for weight-for-age, length/height-for-age, BMI-for-age, head-circumference-for-age, and weight-for-length, based on the WHO Child Growth Standards. The original data are returned together with the calculated metrics.
This function is included in the cdcanthro package because CDC recommends using (1) the CDC Growth Charts for children with ages (months) >=24 and < 240, and (2) the WHO Standards for children < 24 months of age. The use of these different charts, along with the change from recumbent length to standing height at age 2.0 y, creates discontinuities at age 2.0 years (730 days). https://www.cdc.gov/growth-chart-training/hcp/overview/recommended.html
Because this function is written using data.table it's much faster than some other packages that calculate WHO z-scores.
Usage
who_z(data,
agedays = agedays,
wt = wt,
lenhei = lenhei,
bmi = bmi,
headc = headc,
sex_code = 1:2)
Arguments
data |
a |
agedays |
age in completed days. Note that all arguments can be unquoted (e.g., agedays = days) or quoted(agedays = 'days'). If age is given as completed number of months (e.g., NHANES), add 0.5 months, multiply by 30.4375 to convert to agedays, and round to the nearest day. |
wt |
weight in kg. |
lenhei |
recumbent length (ages <= 730 days) or standing height
(ages > 730 days), in cm. Note that there is an ~0.7 cm difference in M (median) between
730 and 731 days in the reference data, when the measurement changes from
recumbent length to standing height. The reference data contain |
bmi |
body mass index, kg/m^2. If not supplied but both |
headc |
head circumference in cm. |
sex_code |
Numeric, single-digit coding for sex if other than 1 for boys and 2 for girls. Optional. |
Details
Column names can be given with or without quotation marks. Naming the arguments rather than
relying on position is recommended, e.g. who_z(d, agedays = age, wt = weight);
otherwise a value can silently land in the wrong slot.
Any absent measurement is skipped, and its z-score is not returned.
The function expects the child's sex to be named sex; either upper- or
lower-case is fine. You cannot have both SEX and sex in your data.
Values can be coded as boys/girls, b/g, male/female,
m/f, or 1/2. Character values can be upper- or lower-case, and
only the first character is considered. Be aware that a code of 'missing' will be interpreted
as a boy.
If sex is numeric and not coded as 1/2, specify this in the optional sex_code argument;
the code for boys is the first number. For example, 0/1 coding would be specified
as sex_code = 0:1 or sex_code = c(0,1).
At least one of wt, lenhei, bmi or headc must be present. Metrics that cannot
be calculated from the supplied variables are silently omitted from the output. If a supplied
column name doesn't exist in data (a likely typo), a warning is issued.
Age in the WHO reference data goes from 0 to 1856 days (1856/365.25 = 5.08 y), but calculations in who_z go up to 1826 days (4.993 y). Weight-for-length Z is calculated only for children <= 730 days of age with a length between 45 and 110 cm.
Value
A data.table, tibble, or dataframe containing the original data plus the calculated metrics.
WHO Z-scores:
-
who_waz: weight-for-sex/age -
who_lhaz: length (or height) for sex/age -
who_wflz: weight-for-length for sex -
who_bmiz: BMI-for-sex/age -
who_headcz: head circumference for sex/age
BIV flags, following the anthro package. Each 'f' (flag) is 1 if the z-score is outside the WHO plausibility range, 0 if inside, and NA if the z-score is NA:
-
fwaz: 1 ifwho_waz< -6 or > 5 -
flhaz: 1 ifwho_lhaz< -6 or > 6 -
fwflz: 1 ifwho_wflz< -5 or > 5 -
fbmiz: 1 ifwho_bmiz< -5 or > 5 -
fheadcz: 1 ifwho_headcz< -5 or > 5
Note that there doesn't appear to be any publication that justifies these cutpoints. While values outside these ranges are outliers, the measurement may be correct.
Author(s)
David Freedman DavidSFreedman@gmail.com
References
World Health Organization, Department of Nutrition for Health and Development. WHO Child Growth Standards: Length/height-for-age, weight-for-age, weight-for-length, weight-for-height, and body mass index-for-age. Methods and Development. Geneva; 2006. https://apps.who.int/iris/handle/10665/43413
The reference WHO LMS values for weight-for-age are in the 'Expanded Tables' files at https://www.who.int/tools/child-growth-standards/standards/weight-for-age. Reference values for the other measures are in the left column.
See Also
cdc_z for standardized values based on the CDC growth charts
Examples
NHanes
d <- data.table::copy(NHanes)
d[, let(lenhei=data.table::fifelse(agedays<=730,length,ht))]
# lenhei is a composite of length and ht:
# it is length for 0 to <=730 days, but height for >730 days
d <- d[agedays <= 1826]
out <- who_z(d, agedays, wt, lenhei, bmi, headc)
head(out)
# verify that the function works for head circumference (small N)
temp <- NHanes[!is.na(headc)]
temp[, let(lenhei=data.table::fifelse(agedays<=730,length,ht))]
out <- who_z(temp, agedays, wt, lenhei, bmi, headc)
head(out)