| Type: | Package |
| Title: | Pulmonary Function Test Interpretation per ERS/ATS 2022 |
| Version: | 1.0.1 |
| Description: | Computes predicted values and lower/upper limits of normal for pulmonary function tests according to American Thoracic Society ('ATS') and European Respiratory Society ('ERS') reference standards. Supports spirometry (Global Lung Function Initiative 'GLI' 2012, Quanjer et al. (2012) <doi:10.1183/09031936.00080312>; and the race-neutral 'GLI' 2022 / 'GLI Global' equations, Bowerman et al. (2023) <doi:10.1164/rccm.202205-0963OC>), static lung volumes ('GLI' 2021, Hall et al. (2021) <doi:10.1183/13993003.00289-2020>), and the carbon monoxide transfer factor / diffusion capacity ('GLI' 2017, Stanojevic et al. (2017) <doi:10.1183/13993003.00010-2017>, including the 2020 author correction <doi:10.1183/13993003.50010-2017>). Also assigns interpretive pattern labels (Normal, Non-specific, Obstructed, Restricted, Mixed) from spirometry and lung-volume measurements following the 'ERS'/'ATS' 2022 interpretation algorithm, Stanojevic et al. (2022) <doi:10.1183/13993003.01499-2021>. |
| License: | MIT + file LICENSE |
| URL: | https://github.com/overdodactyl/pft |
| BugReports: | https://github.com/overdodactyl/pft/issues |
| Encoding: | UTF-8 |
| LazyData: | true |
| RoxygenNote: | 7.3.2 |
| Depends: | R (≥ 4.1) |
| Imports: | rlang, tibble |
| Suggests: | broom, covr, dplyr, ggplot2, knitr, rmarkdown, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| NeedsCompilation: | no |
| Packaged: | 2026-07-04 18:12:32 UTC; m208076 |
| Author: | Pat Johnson |
| Maintainer: | Pat Johnson <johnson.pat@mayo.edu> |
| Repository: | CRAN |
| Date/Publication: | 2026-07-11 08:30:13 UTC |
pft: Pulmonary Function Test Interpretation per ERS/ATS 2022
Description
pft implements the Stanojevic 2022 ERS/ATS interpretive standard
for pulmonary function tests. Reference values come from the GLI
family of equations (GLI 2012 and GLI Global 2022 spirometry,
GLI 2021 static lung volumes, GLI 2017 TLCO with the 2020 author
correction). On top of those, the package computes z-scores and
percent predicted, severity grading, ATS pattern classification,
bronchodilator response per the 2022 criterion, PRISm screening,
conditional change scores for serial measurements, GOLD COPD
severity grading, Graham 2019 spirometry quality grades, and a
ggplot2-based clinical lollipop figure.
Input data format
Every reference function (pft_spirometry(), pft_volumes(),
pft_diffusion(), pft_interpret()) reads from canonical column
names (sex, age, height, and – for GLI 2012 – race) by
default. If your data frame names them differently, point at them
explicitly via tidyverse-style column references:
pft_spirometry(d, sex = Sex, age = Age_y,
height = Ht_cm, race = Ancestry)
Bare names, strings (sex = "Sex"), and rlang injection
(sex = !!my_var) are all accepted. The user's original column
names are preserved in the output.
Optional <measure>_measured, <measure>_pre, and
<measure>_post columns unlock z-score, percent-predicted, and
bronchodilator-response outputs respectively; these are looked up
by literal name (not overridable). See vignette("input-format")
for a walkthrough.
Conventions used throughout
To support unambiguous clinical and research use, the following conventions hold across every exported function:
-
Sex is canonically coded as the character string
"M"or"F". Common variants ("male","Female","m","woman", etc.) are auto-normalised with a warning. Truly unrecognised values ("X","Unknown", etc.) are treated as missing. -
Age is in years (decimal allowed).
-
Height is in centimetres.
-
Volumes (FEV1, FVC, FRC, TLC, RV, ERV, IC, VC) are in litres.
-
DLCO / TLCO are reported in the units the function emits (controlled by
SI.unitsinpft_diffusion()). -
z-scores use the LMS-based formula
z = ((measured / M)^L - 1) / (L * S)and are SIGNED such that values below 0 are below the predicted median. -
Lower limit of normal (LLN) is the 5th percentile of the reference distribution; upper limit of normal (ULN) is the 95th percentile. Both correspond to z-scores of -1.645 and +1.645 respectively.
-
NA handling: rows missing
sex,age, orheightget all-NA outputs. The same applies forracein the GLI 2012 path. Other NA inputs propagate naturally through arithmetic. -
The 4-character pattern combination emitted by
pft_classify()uses positions FEV1, FVC, FEV1/FVC, TLC, in that order, with"A"denoting below the LLN and"N"denoting at or above. So"NNAN"means only FEV1/FVC is below its LLN.
Implemented reference standards
-
Spirometry, GLI 2012: Quanjer et al. Eur Respir J 2012;40(6):1324-43. doi:10.1183/09031936.00080312.
-
Spirometry, GLI Global 2022: Bowerman et al. Am J Respir Crit Care Med 2023;207(6):768-74. doi:10.1164/rccm.202205-0963OC.
-
Static lung volumes, GLI 2021: Hall et al. Eur Respir J 2021;57(3):2000289. doi:10.1183/13993003.00289-2020.
-
Carbon-monoxide transfer factor, GLI 2017: Stanojevic et al. Eur Respir J 2017;50(3):1700010. doi:10.1183/13993003.00010-2017. The 2020 author correction (doi:10.1183/13993003.50010-2017) is the version implemented.
-
Spirometry acquisition standard 2019: Graham et al. Am J Respir Crit Care Med 2019;200(8):e70-e88. doi:10.1164/rccm.201908-1590ST. Implemented by
pft_quality(). -
Interpretive strategy 2022: Stanojevic et al. Eur Respir J 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. Implemented by
pft_classify(),pft_severity(),pft_bdr(),pft_prism(),pft_change(), andpft_interpret(). -
COPD severity: Global Initiative for Chronic Obstructive Lung Disease (GOLD). https://goldcopd.org. Implemented by
pft_gold(). -
Predecessor interpretive strategy 2005: Pellegrino et al. Eur Respir J 2005;26(5):948-68. doi:10.1183/09031936.05.00035205. Cited for historical comparison in
pft_classify().
Scope and limitations
pft does not currently cover:
Reference equations outside the GLI family (NHANES III, JRS, ECSC, Knudson, Crapo, Hankinson, etc.). Use the rspiro package for NHANES III and JRS.
Ethnic groups outside the five recognised by GLI 2012 (Caucasian, African American, North-East Asian, South-East Asian, Other/mixed). The GLI Global 2022 equations are race-neutral and apply across ancestral groups.
Pre-school spirometry (ages < 3).
Bronchial challenge testing (PC20 methacholine, mannitol).
Cardiopulmonary exercise testing.
Six-minute walk test interpretation.
Sleep-study integration.
Pediatric-specific bronchodilator-response thresholds (the 2022 adult criterion is applied uniformly).
Sub-patterns within the Stanojevic 2022 algorithm that the coarse 5-category classifier doesn't enumerate (Dysanapsis, etc.). The package's
pft_classify()folds Dysanapsis into "Obstructed" when FEV1/FVC is below its LLN.Altitude corrections to DLCO. (Haemoglobin correction is supported – see
pft_dlco_hb_correct().)Sex categories outside
"M"and"F".
Outputs are intended for research and education. Clinical decisions
should be made by qualified clinicians using validated tools; pft
is not FDA-cleared, not a medical device, and not validated for
diagnostic decision-making.
Reproducibility
Every internal reference-equation coefficient and spline-table value
in R/sysdata.rda is reproducibly built from the corresponding
official ERS / AJRCCM source document via the scripts in
data-raw/build_gli_*.R. The source PDFs and supplement workbooks
are not redistributed with the package (they are copyrighted
publisher content); the build scripts document where to obtain them.
Citation
Run citation() (i.e. citation("pft")) to retrieve a bibentry
for the package alongside the source reference standards.
Author(s)
Maintainer: Pat Johnson johnson.pat@mayo.edu (ORCID)
Authors:
Scott Helgeson (ORCID)
Other contributors:
Zach Quicksall [contributor]
Jairo Pena [contributor]
See Also
Useful links:
Bronchodilator response per the ERS/ATS 2022 criterion
Description
Classifies bronchodilator response (BDR) by the percent change in the measured value relative to the patient's predicted value, as recommended by Stanojevic et al. ERJ 2022. Significant BDR is defined as a post-bronchodilator increase of more than 10% of the predicted value in either FEV1 or FVC. This replaces the 2005 standard, which used a >=12% AND >=200 mL change from baseline.
Usage
pft_bdr(pre, post, predicted, threshold = BDR_THRESHOLD_PCT_PRED)
Arguments
pre, post |
Numeric vectors of pre- and post-bronchodilator measurements (same units, same length). |
predicted |
Numeric vector of predicted (median) values for the
same measure, typically the |
threshold |
Percent-of-predicted change considered significant. Defaults to 10 (the Stanojevic 2022 criterion). |
Value
A data frame with one row per input observation and columns:
-
pct_pred_change:(post - pre) / predicted * 100. -
is_significant: logical,TRUEwhenpct_pred_change > threshold.NAis propagated wherever any ofpre,post,predictedisNA.
Column naming
This function's pct_pred_change column is percent-of-predicted
change (the 2022 criterion). The predecessor pft_bdr_2005() emits a
similarly-named but different column, pct_change, which is
percent-of-baseline change ((post - pre) / pre * 100, the 2005
criterion). The two functions deliberately use distinct column names
so a result frame can carry both without ambiguity.
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. See the "Bronchodilator responsiveness testing" section.
See Also
pft_spirometry() to obtain the predicted FEV1 / FVC values
used as the denominator. pft_interpret() runs BDR automatically
when <measure>_pre and <measure>_post columns are present.
Examples
pft_bdr(pre = 2.5, post = 3.0, predicted = 4.0)
# -> 12.5% of predicted change, is_significant = TRUE
Bronchodilator response per the Pellegrino 2005 standard
Description
Classifies bronchodilator response (BDR) by the Pellegrino et al.
ERJ 2005 dual criterion: significant if both the relative change
from baseline is at least 12% AND the absolute change is at least
200 mL. Replaced in 2022 by pft_bdr()'s simpler
"> 10% of predicted" rule.
Usage
pft_bdr_2005(pre, post)
Arguments
pre, post |
Numeric vectors of pre- and post-bronchodilator measurements, in litres, same length. |
Value
A data frame with one row per input observation and three
columns: pct_change (i.e. (post - pre) / pre * 100),
abs_change (i.e. post - pre in litres), and is_significant
(logical, TRUE when pct_change > 12 AND abs_change > 0.2,
both inequalities strict per the paper's wording on p. 959:
"(>12% of control and >200 mL)"). NA propagates wherever
either of pre / post is NA.
Column naming
This function's pct_change column is percent-of-baseline
change (the 2005 criterion). The 2022 pft_bdr() emits a
similarly-named but different column, pct_pred_change, which is
percent-of-predicted change ((post - pre) / predicted * 100,
the 2022 criterion). The two functions deliberately use distinct
column names so a result frame can carry both without ambiguity.
References
Pellegrino R, Viegi G, Brusasco V, et al. Interpretative strategies for lung function tests. Eur Respir J. 2005;26(5):948-968. doi:10.1183/09031936.05.00035205. Criterion stated in the "Bronchodilator response" section (p. 958) and disambiguated on p. 959.
See Also
pft_bdr() for the current Stanojevic 2022 criterion
(>10% of predicted). Unlike the 2022 form, the 2005 version does
not need the patient's predicted FEV1 / FVC – only the pre and
post measurements.
Examples
pft_bdr_2005(pre = c(2.5, 2.0), post = c(2.8, 2.1))
# -> first row significant (>=12% AND >=200 mL),
# second row not (only 5% and 100 mL increase)
Conditional change score for serial PFT measurements
Description
pft_change() computes the conditional change score (CCS) defined
in Box 2 of the Stanojevic et al. ERS/ATS 2022 interpretation
standard. The CCS evaluates whether the change between two FEV1
z-scores is larger than would be expected from within-subject
variability and regression to the mean alone.
Formula (paper Box 2 p. 12):
CCS = (z_2 - r \cdot z_1) / \sqrt{1 - r^2}
Where the autocorrelation r is itself a function of the time
interval between measurements and the patient's age at the first
time point:
r = 0.642 - 0.04 \cdot time(years) + 0.020 \cdot age(years)
Changes within +/- 1.96 change scores are considered within the
normal limits per the paper.
This formula was derived from a children/young-people cohort
(Stanojevic 2022 references the underlying study and notes the
approach has "yet to be validated, extended to adults" but
permits its use as "a reasonable tool to facilitate
interpretation"). For adults the 2022 standard alternatively
recommends FEV1Q (Box 3); see pft_fev1q().
Usage
pft_change(z1, z2, age_t1 = NULL, time_years = NULL, r = NULL)
Arguments
z1, z2 |
Numeric vectors of FEV1 z-scores at time 1 and time 2. |
age_t1 |
Numeric. Patient age (in years) at the first measurement. |
time_years |
Numeric. Elapsed time between measurements in years (e.g. 0.25 for 3 months, 4 for 4 years). |
r |
Optional. Numeric in |
Value
A data frame with columns:
-
ccs: the conditional change score. -
r_used: the autocorrelation actually used in the calculation (returned so callers can audit the value chosen). -
is_significant: logical,TRUEwhen|ccs| > 1.96(i.e. outside the paper's normal-limits range).
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. Box 2 (p. 12).
See Also
pft_spirometry() to produce the FEV1 z-scores at each
time point.
Examples
# Stanojevic 2022 Box 2 worked example: a 14-year-old male whose
# FEV1 z-score dropped from -0.78 to -1.60 over 3 months.
pft_change(z1 = -0.78, z2 = -1.60, age_t1 = 14, time_years = 0.25)
# -> r_used = 0.912, ccs ~= -2.17, is_significant = TRUE
# Same drop spread over 4 years
pft_change(z1 = -0.78, z2 = -1.60, age_t1 = 14, time_years = 4)
# -> r_used = 0.762, ccs ~= -1.55, is_significant = FALSE
Classify ATS spirometry patterns from spirometry and lung-volume measurements
Description
pft_classify() assigns ATS patterns using spirometry and lung volume data.
By default it applies the Stanojevic et al. ERS/ATS 2022 algorithm
(Figure 8); pass standard = "2005" to apply the predecessor
Pellegrino et al. ERJ 2005 algorithm.
Typically called via pft_interpret() as part of the one-call
workflow; exported for callers who want to apply the classifier to
pre-computed columns directly.
Usage
pft_classify(
data,
standard = c("2022", "2005"),
year = 2022,
fev1 = fev1,
fev1_lln = NULL,
fvc = fvc,
fvc_lln = NULL,
fev1fvc = fev1fvc,
fev1fvc_lln = NULL,
tlc = tlc,
tlc_lln = tlc_lln
)
Arguments
data |
A data frame containing the six spirometry input columns
( |
standard |
Which interpretive standard's classifier to apply.
|
year |
GLI year suffix to use when looking up the spirometry
LLN columns ( |
fev1, fev1_lln, fvc, fvc_lln, fev1fvc, fev1fvc_lln, tlc, tlc_lln |
Column references for the eight inputs. Defaults are the canonical
names ( |
Value
The original data frame with two appended columns:
-
ats_classification: pattern label. Values depend on the selectedstandard; see above. -
ats_pattern_combination: a 4-character string in fixed column order FEV1, FVC, FEV1/FVC, TLC, with"A"denoting the value is below its LLN,"N"denoting it is at or above, and"?"denoting the value (and its LLN) was missing. So"NNAN"means only FEV1/FVC is below its LLN (pure airway obstruction);"AANA"means FEV1, FVC, and TLC are all low while FEV1/FVC is preserved (restriction);"NNA?"means FEV1/FVC is below LLN and TLC is unknown. The pattern-combination string is independent of thestandardselected.
Column-name overrides
Each column-reference argument accepts three forms:
a bare column name –
fev1 = my_fev1a string –
fev1 = "my_fev1"an injected value –
fev1 = !!my_varwheremy_var <- "my_fev1"
Defaults are the canonical pft column names, so callers whose data
already follows the convention pass no extra arguments. The two TLC
references (tlc, tlc_lln) are optional: when either resolves to
a column not present in data, the spirometry-only fallback
triggers without raising an error.
Missing TLC (spirometry-only fallback)
When the three spirometry inputs (fev1, fvc, fev1fvc) and
their LLNs are all present but TLC is missing, pft_classify()
falls back to a spirometry-only branch instead of returning NA.
Under both standards, an "Obstructed" row is still recognisable
from FEV1/FVC < LLN alone (Mixed would require TLC to distinguish
but Mixed is itself an obstructive defect, so the row is labelled
"Obstructed"). Under the 2005 standard, rows with FVC \ge
LLN classify deterministically because the 2005 flowchart does not
consult TLC in that branch (so "Normal" is emitted for normal
spirometry). Cells where TLC would have been the disambiguating
input (Normal vs Restricted, Non-specific vs Restricted under
2022; Normal vs Restricted, Obstructed vs Mixed under 2005) remain
NA. Rows where any spirometry input is itself missing always
return NA. See pft_prism() for the spirometry-only PRISm
screen which is reported as a separate logical column.
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. The 2022 classifier follows the spirometry interpretation flowchart in Figure 8 and the pattern definitions in Tables 5 and 8.
Pellegrino R, Viegi G, Brusasco V, et al. Interpretative strategies for lung function tests. Eur Respir J. 2005;26(5):948-968. doi:10.1183/09031936.05.00035205. The 2005 classifier follows Figure 2.
See Also
pft_prism() for the spirometry-only PRISm screen (no TLC
required). pft_severity() / pft_severity_2005() grade
per-measure severity. pft_interpret() runs the classifier as
part of the one-call workflow and also accepts the standard
argument for end-to-end reclassification.
Examples
data <- data.frame(fev1 = c(3.453, 2.385),
fev1_lln_2022 = c(3.303, 3.384),
fvc = c(4.733, 3.485),
fvc_lln_2022 = c(4.214, 4.24),
fev1fvc = c(0.600, 0.827),
fev1fvc_lln_2022 = c(0.681, 0.700),
tlc = c(1.5, 2.3),
tlc_lln = c(2, 2.5))
pft_classify(data)
pft_classify(data, standard = "2005")
# Column-name override: data using non-canonical names.
alt <- data.frame(my_fev1 = 3.0, my_fev1_lln = 2.5,
fvc = 4.0, fvc_lln_2022 = 3.5,
fev1fvc = 0.65, fev1fvc_lln_2022 = 0.70,
tlc = 6.0, tlc_lln = 5.0)
pft_classify(alt, fev1 = my_fev1, fev1_lln = my_fev1_lln)
Compute carbon monoxide diffusion capacity or transfer factor reference values for given demographics
Description
pft_diffusion() computes ATS-compliant upper and lower normal limits
for carbon monoxide measured diffusion capacity and European equivalents
including DLCO (or TLCO), KCO, and VA.
Usage
pft_diffusion(data, SI.units = FALSE, sex = sex, age = age, height = height)
Arguments
data |
A data frame containing columns for sex ("M","F"),
age (in years, in the range 5-90 per the GLI 2017 spline
tables) and height (in centimeters).
If |
SI.units |
A boolean. Returns the reference values in SI units if TRUE . and Traditional units if FALSE. |
sex, age, height |
Column references. By default |
Value
The original data frame with extra columns appended for each measure:
-
<measure>_pred: predicted (median) value. -
<measure>_lln: lower limit of normal (5th percentile). -
<measure>_uln: upper limit of normal (95th percentile). If a<measure>_measuredcolumn was supplied indata, two additional columns are emitted: -
<measure>_zscore: LMS z-score((measured/M)^L - 1) / (L*S). -
<measure>_pctpred: percent predicted(measured / pred) * 100.
References
Stanojevic S, Graham BL, Cooper BG, et al. Official ERS technical standards: Global Lung Function Initiative reference values for the carbon monoxide transfer factor for Caucasians. Eur Respir J. 2017;50(3):1700010. doi:10.1183/13993003.00010-2017. (Author correction: doi:10.1183/13993003.50010-2017, applied here.)
See Also
pft_spirometry() and pft_volumes() for the analogous
reference-value functions. pft_severity() grades DLCO impairment
severity from the z-score column produced here. pft_interpret()
composes all three reference functions in one call.
Examples
data <- data.frame(sex=c("M","F"),
age=c(30,5.1),
height=c(178,50))
pft_diffusion(data)
Classify a diffusion result into a clinical pattern category
Description
Takes per-patient dlco_zscore, va_zscore, and kco_zscore
columns (the outputs of pft_diffusion() when _measured columns
are supplied) and assigns a clinical interpretive category per the
Hughes & Pride 2012 framework adopted by the ERS/ATS Stanojevic
2017 task force.
Usage
pft_diffusion_interpret(
data,
SI.units = FALSE,
dlco = NULL,
va = NULL,
kco = NULL
)
Arguments
data |
A data frame containing the three z-score input columns. |
SI.units |
Logical, default |
dlco, va, kco |
Column references for the three z-score inputs.
|
Details
The classifier consumes z-scores only and is unit-agnostic, but the
default input column names differ between unit systems. Set
SI.units = TRUE to pick up the SI-units column set
(tlco_zscore, va_zscore, kco_si_zscore); otherwise the
traditional-units column set (dlco_zscore, va_zscore,
kco_tr_zscore) is used. Override individual column names via the
dlco / va / kco arguments.
Typically called via pft_interpret() as part of the one-call
workflow; exported for callers who want to apply the classifier to
pre-computed z-score columns directly.
Value
The original data frame with a single appended column:
diffusion_category. Possible values:
"Normal"All three z-scores above LLN.
"Parenchymal"Low DLCO, low KCO, normal VA.
"Volume loss"Low DLCO, low VA, normal or elevated KCO.
"Mixed"Low DLCO, low VA, low KCO.
"Vascular (suggested)"Low DLCO, normal VA, low or elevated KCO.
"Elevated KCO"Normal DLCO with elevated KCO (z > +1.645).
"Other"Combination not matching any of the above patterns (e.g., low VA in isolation).
NARequired z-score columns missing.
The category labels describe the z-score pattern only; differential diagnosis is left to the clinician (see the Hughes & Pride 2012 source paper for clinical interpretation).
Column-name overrides
Each column-reference argument accepts three forms:
a bare column name –
dlco = my_dlcoa string –
dlco = "my_dlco"an injected value –
dlco = !!my_varwheremy_var <- "my_dlco"
dlco and kco default to NULL, which selects the canonical
name based on SI.units (traditional or SI). Passing an explicit
reference overrides this selection.
References
Hughes JM, Pride NB. Examination of the carbon monoxide diffusing capacity (DL(CO)) in relation to its KCO and VA components. Am J Respir Crit Care Med. 2012;186(2):132-139. doi:10.1164/rccm.201112-2160CI.
Stanojevic S, Graham BL, Cooper BG, et al. ERS/ATS technical standard: Global Lung Function Initiative reference values for the carbon monoxide transfer factor for Caucasians. Eur Respir J. 2017;50:1700010. doi:10.1183/13993003.00010-2017. (Provides the z-score reference standard whose LLN at z = -1.645 is used here. The clinical interpretation framework is from Hughes & Pride 2012, adopted by the 2017 task force.)
See Also
pft_diffusion() to compute the input z-scores;
pft_interpret() for the one-call workflow that auto-runs this
classifier when diffusion outputs are present.
Examples
# Three patients: normal, parenchymal (low DLCO/KCO, normal VA),
# and volume loss (low DLCO/VA, normal KCO).
d <- data.frame(
dlco_zscore = c(-0.5, -2.0, -2.0),
va_zscore = c(-0.5, -0.5, -2.0),
kco_tr_zscore = c(-0.5, -2.0, -0.5)
)
pft_diffusion_interpret(d)
# SI units (TLCO / KCO_SI). Pass SI.units = TRUE.
d_si <- data.frame(
tlco_zscore = c(-0.5, -2.0),
va_zscore = c(-0.5, -0.5),
kco_si_zscore = c(-0.5, -2.0)
)
pft_diffusion_interpret(d_si, SI.units = TRUE)
Adjust a measured DLCO / TLCO for the patient's hemoglobin
Description
Applies the Cotes 1972 hemoglobin correction to a measured carbon
monoxide transfer factor (DLCO or TLCO), returning the value that
would have been measured if the patient's hemoglobin equaled the
age- and sex-specific reference. The correction is intended for
clinical interpretation: after applying it, the corrected DLCO can
be passed to pft_diffusion() (whose reference equations assume
the reference Hb).
Usage
pft_dlco_hb_correct(dlco, hemoglobin, sex, age = NA_real_)
Arguments
dlco |
Numeric vector of measured DLCO or TLCO values, any unit system (the correction is multiplicative and unit-agnostic). |
hemoglobin |
Numeric vector of measured hemoglobin in g/L (routine clinical adult range 120-160 g/L). Pass g/L directly; the function does not detect or convert g/dL inputs. |
sex |
Character vector ("M"/"F"). Soft-corrected via
the internal |
age |
Optional numeric vector. When supplied, males aged < 15
yr use the female / child reference (134 g/L) per Stanojevic
2017 p. 11. When omitted (the default |
Details
Stanojevic et al. ERJ 2017 explicitly recommends (Table 4 p. 9) that the published GLI TLCO reference values be uncorrected for Hb, with Hb levels considered separately during interpretation. This function provides that interpretive step.
Formula (Cotes 1972; reformulated from Stanojevic 2017 p. 9, with constants 1.7 and 0.7 reflecting the membrane / capillary diffusing capacity ratio of 0.7 mL min^-1 mmHg^-1 mL-blood^-1):
TLCO_{Hb} = TLCO_{measured} \times \frac{1.7 \cdot Hb_{ref}}{Hb + 0.7 \cdot Hb_{ref}}
Reference Hb levels (Stanojevic 2017 p. 11):
Males aged >= 15 yr: 146 g/L
Females (any age) and children < 15 yr: 134 g/L
When hemoglobin == Hb_ref the correction factor is exactly 1
(no adjustment). Anaemic patients (hemoglobin < Hb_ref) receive
an UPWARD correction reflecting that less Hb means less CO uptake
and a depressed measured value.
Value
Numeric vector of Hb-corrected DLCO / TLCO values, same
units as dlco. NA propagates from any input.
References
Stanojevic S, Graham BL, Cooper BG, et al. Official ERS technical standards: Global Lung Function Initiative reference values for the carbon monoxide transfer factor for Caucasians. Eur Respir J. 2017;50(3):1700010. doi:10.1183/13993003.00010-2017. Hb correction is discussed on p. 9 and the Cotes formula context on p. 11.
Cotes JE, Dabbs JM, Elwood PC, et al. Iron-deficiency anaemia: its effect on transfer factor for the lung (diffusing capacity) and ventilation and cardiac frequency during sub-maximal exercise. Clin Sci. 1972;42:325-335.
See Also
pft_diffusion() for the reference-value computation that
consumes the Hb-corrected DLCO.
Examples
# An anaemic adult male (Hb = 100 g/L vs reference 146 g/L) with
# measured DLCO of 20 mL/min/mmHg has a Hb-adjusted DLCO of
# 20 x (1.7 x 146) / (100 + 0.7 x 146) ~= 24.55.
pft_dlco_hb_correct(dlco = 20, hemoglobin = 100,
sex = "M", age = 40)
# No-op when Hb equals reference.
pft_dlco_hb_correct(20, hemoglobin = 146, sex = "M")
# Children use the female / child reference (134 g/L) regardless
# of sex.
pft_dlco_hb_correct(20, hemoglobin = 134, sex = "M", age = 10)
Synthetic example PFT cohort
Description
A small synthetic cohort of 20 patients spanning the clinical patterns the package classifies (Normal, Obstructed, Restricted, Mixed, Non-specific, PRISm) plus a few bronchodilator-response cases. Demographics are random within plausible ranges; measured values were hand-picked so that each row lands in its target pattern after the GLI reference equations are applied.
Usage
pft_example
Format
A tibble with 20 rows and 11 columns:
- patient_id
Integer 1-20. Synthetic identifier.
- sex
Character:
"M"or"F".- age
Numeric, years.
- height
Numeric, centimetres.
- race
One of
"Caucasian","AfrAm","NEAsia","SEAsia".- fev1_measured
Measured FEV1 in litres. May be
NA.- fvc_measured
Measured FVC in litres.
- fev1fvc_measured
Measured FEV1/FVC ratio.
- tlc_measured
Measured TLC in litres. May be
NAfor rows intended to demonstrate spirometry-only workflows.- fev1_pre
Pre-bronchodilator FEV1 in litres.
NAwhen not a BDR scenario.- fev1_post
Post-bronchodilator FEV1 in litres.
NAwhen not a BDR scenario.
Details
No real patient data. Generated by
data-raw/build_pft_example.R. Provided for examples, vignettes,
and quick experimentation.
Source
data-raw/build_pft_example.R (synthetic; no real patient data).
Examples
data(pft_example)
head(pft_example)
pft_interpret(pft_example)
FEV1Q: ratio of FEV1 to a sex-specific survivable lower limit
Description
Computes the FEV1Q survival index proposed by Miller & Pedersen (ERJ 2010) and discussed as an adult alternative to the conditional change score in Box 3 (p. 13) of the Stanojevic et al. ERJ 2022 interpretation standard. FEV1Q expresses FEV1 in relation to a "bottom line" required for survival, rather than how far an individual's result is from their predicted value; the race-neutral evidence base was consolidated by Balasubramanian et al. (ERJ 2024).
Usage
pft_fev1q(fev1, sex, age = NA_real_)
Arguments
fev1 |
Numeric vector of FEV1 measurements in litres. |
sex |
Character vector of patient sex. Accepts the soft-
correctable variants from |
age |
Optional numeric vector. When supplied, rows with |
Details
Formula (Box 3 verbatim):
FEV1Q = FEV1 / Q_{sex}
where Q_{male} = 0.5 L and Q_{female} = 0.4 L are the
sex-specific 1st percentiles of the FEV1 distribution in adult
lung-disease populations. The index approximates the number of
turnovers remaining of a lower survivable limit of FEV1; values
closer to 1 indicate greater risk of death.
The 2022 standard cautions (running text on p. 13, immediately
preceding Box 3): "FEV1Q is not appropriate for children and
adolescents." When age is supplied,
rows with age < 18 return NA_real_. When age is omitted, the
age guard is skipped and the caller is responsible for restricting
input to adults.
For longitudinal interpretation in adults the 2022 standard
suggests FEV1Q as an alternative to the conditional change score
(see pft_change()): under normal circumstances 1 unit of FEV1Q is
lost approximately every 18 years (every ~10 years in smokers and
the elderly).
Value
Numeric vector of FEV1Q ratios, same length as fev1. NA
propagates from any input.
References
Miller MR, Pedersen OF. New concepts for expressing forced expiratory volume in 1 s arising from survival analysis. Eur Respir J. 2010;35(4):873-882. doi:10.1183/09031936.00025809. Original proposal of the FEV1Q index and the sex-specific 1st-percentile denominators (0.5 L male, 0.4 L female).
Balasubramanian A, Wise RA, Stanojevic S, Miller MR, McCormack MC. FEV1Q: a race-neutral approach to assessing lung function. Eur Respir J. 2024;63(4):2301622. doi:10.1183/13993003.01622-2023. Race-neutral validation of the FEV1Q index.
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. Discusses FEV1Q in Box 3 (p. 13) as an adult alternative to the conditional change score.
See Also
pft_change() for the conditional change score (the
children / young-people sibling); pft_severity() for the
z-score-based severity grading.
Examples
# Stanojevic 2022 Box 3 worked example: a 70-year-old woman with
# FEV1 of 0.9 L has FEV1Q of 0.9 / 0.4 = 2.25.
pft_fev1q(0.9, "F", age = 70)
# Vectorised across sex.
pft_fev1q(c(1.0, 1.0), c("M", "F"))
# Adolescents return NA when age is supplied.
pft_fev1q(1.0, "F", age = 10)
Grade COPD severity by GOLD criteria
Description
Returns the GOLD spirometric severity grade (1-4) for one or more patients given their FEV1 expressed as a percent of predicted, optionally enforcing the GOLD-mandated prerequisite of confirmed airflow obstruction (FEV1/FVC < 0.7).
Usage
pft_gold(fev1_pctpred, fev1fvc = NA_real_)
Arguments
fev1_pctpred |
Numeric vector of FEV1 % predicted values (e.g.
the |
fev1fvc |
Optional numeric vector of post-bronchodilator
FEV1/FVC ratios (e.g. the |
Details
GOLD severity grades for airflow obstruction (Figure 2.10 of the GOLD 2026 report, content page 38):
| Grade | Severity | FEV1 % predicted |
| GOLD 1 | Mild | >= 80 |
| GOLD 2 | Moderate | >= 50 and < 80 |
| GOLD 3 | Severe | >= 30 and < 50 |
| GOLD 4 | Very severe | < 30
|
GOLD specifies the prerequisite "In patients with COPD (FEV1/FVC <
0.7)" explicitly above Figure 2.10's grade table; the surrounding
text (content p. 37) repeats this requirement. Supplying fev1fvc
enforces the GOLD fixed-cutoff prerequisite. Callers wanting an
LLN-based prerequisite instead should use pft_classify() to
identify obstructed patients and mask pft_gold() output by hand.
Value
Character vector with values "GOLD 1", "GOLD 2",
"GOLD 3", "GOLD 4", or NA. NA is returned for rows with
missing fev1_pctpred OR (when fev1fvc is supplied) rows that
fail the airflow-obstruction prerequisite.
References
Global Initiative for Chronic Obstructive Lung Disease (GOLD). Global Strategy for the Diagnosis, Management and Prevention of Chronic Obstructive Pulmonary Disease, 2026 Report. Figure 2.10. https://goldcopd.org.
See Also
pft_classify() for LLN-based airflow obstruction
identification (Stanojevic 2022); pft_severity() for the
z-score-based severity scheme (which differs from GOLD's
percent-predicted scheme).
Examples
# Without prerequisite check (backward-compatible): one grade per
# non-NA input.
pft_gold(c(85, 65, 40, 25))
# -> "GOLD 1" "GOLD 2" "GOLD 3" "GOLD 4"
# With prerequisite check: the third patient has FEV1/FVC = 0.75
# (no airflow obstruction) and is returned NA.
pft_gold(c(85, 65, 40, 25), fev1fvc = c(0.65, 0.60, 0.75, 0.55))
# -> "GOLD 1" "GOLD 2" NA "GOLD 4"
Comprehensive ERS/ATS 2022 PFT interpretation in one call
Description
pft_interpret() is a single-call workflow that combines every
interpretation primitive in this package into a complete clinical
report per the Stanojevic et al. ERJ 2022 standard. It auto-detects
which computations are possible from the input columns and skips
anything it cannot do:
If sex / age / height (and race, for
year = 2012) are present, it computes spirometry reference values viapft_spirometry().If sex / age / height are present, it computes lung-volume reference values via
pft_volumes().If sex / age / height are present, it computes diffusion reference values via
pft_diffusion().For each measure whose
_measuredcolumn is present, z-score and percent-predicted are appended (see the individual reference functions for details).For each measure with a z-score, a
<measure>_severitycolumn is appended viapft_severity().If
fev1_measured,fvc_measured,fev1fvc_measured, andtlc_measuredcolumns are present, the ATS pattern classifier (pft_classify()) labels each row.If
tlc_measured,rv_tlc_measured, andfev1fvc_measuredare present (with their LLNs / ULNs computable), the lung- volume sub-pattern classifier (pft_volume_subpattern()) adds avolume_subpatterncolumn. Whenfrc_tlc_measured/frc_tlc_ulnare also present, both volume ratios are consulted per Stanojevic 2022 Figure 10.If
fev1_measured,fev1fvc_measured, and their LLNs are resolvable,pft_prism()adds aprismflag (independent of TLC).If
<measure>_preand<measure>_postcolumns are present for any spirometry measure,pft_bdr()adds<measure>_bdr_pctand<measure>_bdr_significantcolumns.
This is the recommended entry point for clinical-style reporting; the individual reference and interpretation functions are exported for callers who need finer-grained control.
Usage
pft_interpret(
data,
year = 2022,
SI.units = FALSE,
standard = c("2022", "2005"),
sex = sex,
age = age,
height = height,
race = race
)
Arguments
data |
A data frame containing whatever inputs are available. See Details for the column-name conventions. |
year |
GLI spirometry equation year. Defaults to |
SI.units |
Whether to report diffusion in SI units. See
|
standard |
Interpretive standard whose downstream rules to
apply: |
sex, age, height, race |
Column references. By default
|
Details
To trigger z-scores and percent-predicted on a measure, include the
corresponding <measure>_measured column in data (e.g.
fev1_measured, frc_measured, dlco_measured). To trigger BDR,
include <measure>_pre and <measure>_post columns for any of FEV1,
FVC, FEV1/FVC.
All outputs trace to a specific equation, table, or figure in
Stanojevic et al. ERJ 2022 or the underlying GLI reference papers; see
the @references blocks on the individual functions.
Value
The original data frame with every applicable reference value, z-score, percent predicted, severity grade, pattern label, PRISm flag, and BDR result appended.
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021.
Examples
patient <- data.frame(
sex = "M", age = 45, height = 178, race = "Caucasian",
fev1_measured = 2.5, fvc_measured = 3.8, fev1fvc_measured = 2.5/3.8,
tlc_measured = 6.0
)
pft_interpret(patient)
Pivot a pft_result to long form
Description
Reshapes a wide pft_interpret() / pft_spirometry() / pft_volumes() /
pft_diffusion() output (one row per patient, one column per measure ×
statistic) into long form (one row per (patient, measure, year) with
columns for each statistic). This is the natural shape for dplyr /
ggplot2 faceting, cohort modelling, and broom-style downstream
workflows.
Usage
pft_long(x, ...)
Arguments
x |
A data frame; typically a |
... |
Currently unused; reserved for forward compatibility. |
Details
Discovery is keyed off <measure>_pred columns; the four-digit GLI
year is extracted from the column suffix and recorded in the year
column. Spirometry outputs from pft_spirometry() / pft_interpret()
always carry a year suffix (fev1_pred_2012, fev1_pred_2022, ...)
and produce a populated year; lung-volume (Hall 2021) and
diffusion (GLI 2017) outputs are unsuffixed and produce year = NA
until a competing standard ships and the same suffixing convention
is adopted there. Columns whose suffix does not match a recognised
statistic are ignored, so id / demographic columns are dropped (use
the .patient integer to join back).
Value
A tibble with columns .patient (integer row position),
measure, year (character; NA for non-suffixed outputs),
pred, lln, uln, measured, zscore, pctpred, and
severity. Missing statistics fill with NA of the appropriate
type.
See Also
pft_interpret()
to produce the wide-form input.
Examples
patient <- data.frame(
sex = c("M","F"), age = c(45, 60), height = c(178, 165),
race = "Caucasian",
fev1_measured = c(2.5, 1.8), fvc_measured = c(3.8, 2.4)
)
result <- pft_interpret(patient)
pft_long(result)
Clinical visualisation for a single PFT result
Description
pft_plot() draws a single-patient z-score figure: one row per
measure, points at the patient's z-score, shaded reference bands
for the four Stanojevic 2022 severity grades returned by
pft_severity(): normal (z >= -1.645), mild (-2.5 <= z < -1.645),
moderate (-4 <= z < -2.5), and severe (z < -4). The normal band
extends symmetrically above zero to the upper limit of normal;
values above the ULN are shown but are not a 2022 severity grade.
Requires the ggplot2 package (a Suggested dependency).
Usage
pft_plot(data)
Arguments
data |
A single-row data frame produced by |
Value
A ggplot object.
See Also
pft_interpret() for the input data shape.
Examples
patient <- data.frame(
sex = "M", age = 45, height = 178, race = "Caucasian",
fev1_measured = 2.5,
fvc_measured = 3.8,
fev1fvc_measured = 2.5 / 3.8,
tlc_measured = 6.0
)
pft_plot(pft_interpret(patient))
Screen for Preserved Ratio Impaired Spirometry (PRISm)
Description
PRISm is the spirometry-only manifestation of the "non-specific" pattern when TLC is not available: a low FEV1, a low FVC, and a preserved (normal) FEV1/FVC ratio. The 2022 ERS/ATS interpretation standard (Stanojevic et al.) classifies it in Table 5 with row "Non-specific pattern" (FEV1 reduced, FVC reduced, FEV1/FVC normal).
Typically called via pft_interpret() as part of the one-call
workflow; exported for callers who want to apply the screen to
pre-computed columns directly.
This function adds a prism logical column to the data frame.
PRISm is a spirometry-only screen and does not require a TLC
measurement.
Usage
pft_prism(
data,
year = 2022,
fev1 = fev1,
fev1_lln = NULL,
fvc = fvc,
fvc_lln = NULL,
fev1fvc = fev1fvc,
fev1fvc_lln = NULL
)
Arguments
data |
A data frame containing the six input columns named below. |
year |
GLI year suffix used when looking up the LLN columns
( |
fev1, fev1_lln, fvc, fvc_lln, fev1fvc, fev1fvc_lln |
Column references
for the six required columns. Defaults are the canonical names
( |
Value
The original data frame with a prism logical column
appended. NA propagates from any of the six input columns.
Column-name overrides
Each column-reference argument accepts three forms:
a bare column name –
fev1 = my_fev1a string –
fev1 = "my_fev1"an injected value –
fev1 = !!my_varwheremy_var <- "my_fev1"
Defaults are the canonical pft column names, so callers whose data already follows the convention pass no extra arguments.
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. PRISm appears in Table 5 as the spirometry-only form of the non-specific pattern.
See Also
pft_classify() for the full ATS pattern classification
when TLC is available; pft_interpret() runs both PRISm and
full classification automatically when the relevant columns are
present.
Examples
d <- data.frame(fev1 = 2.0, fev1_lln_2022 = 2.5,
fvc = 2.6, fvc_lln_2022 = 3.0,
fev1fvc = 0.80, fev1fvc_lln_2022 = 0.70)
pft_prism(d)
# Column-name override: data using non-canonical names.
d2 <- data.frame(my_fev1 = 2.0, my_fev1_lln = 2.5,
fvc = 2.6, fvc_lln_2022 = 3.0,
fev1fvc = 0.80, fev1fvc_lln_2022 = 0.70)
pft_prism(d2, fev1 = my_fev1, fev1_lln = my_fev1_lln)
Grade spirometry quality per ATS/ERS 2019
Description
Assigns one of grades A-F to a set of acceptable spirometry maneuvers for a single measure (FEV1 or FVC) per the Graham et al. ATS/ERS 2019 technical standard, Table 10. Grades depend on the number of acceptable maneuvers and the difference between the best two values.
Usage
pft_quality(values, age = NA_real_)
Arguments
values |
Numeric vector of measurements (litres) from each
acceptable maneuver for ONE patient and ONE measure. Length 0 is
allowed and yields grade |
age |
Patient age, in years. The repeatability thresholds tighten
for children aged 6 or younger; the threshold is the greater of
the absolute child value (0.100 / 0.150 / 0.200 L for A / C / D)
and 10% of the highest measured value, per Table 10's footnote.
Defaults to |
Details
Grade definitions (Table 10, paper p. e83). Adult thresholds in
parentheses; child (age <= 6) thresholds are max(absolute, 0.10 · max(values)):
-
A: >= 3 acceptable maneuvers; best two within 0.150 L (0.100 L for child).
-
B: 2 acceptable maneuvers; best two within 0.150 L (0.100 L for child).
-
C: >= 2 acceptable maneuvers; best two within 0.200 L (0.150 L for child).
-
D: >= 2 acceptable maneuvers; best two within 0.250 L (0.200 L for child).
-
E: >= 2 acceptable maneuvers with best-two diff exceeding the D threshold, OR exactly 1 acceptable maneuver.
-
F: 0 acceptable maneuvers.
Grade U ("0 acceptable AND >= 1 usable") from Table 10 is NOT currently distinguished from F. Implementing U would require extending the API to take a separate vector of usable-but-not- acceptable maneuvers; with zero acceptable values, the function returns F unconditionally.
Value
A length-1 character with value "A", "B", "C", "D",
"E", or "F".
References
Graham BL, Steenbruggen I, Miller MR, et al. Standardization of Spirometry 2019 Update. An Official American Thoracic Society and European Respiratory Society Technical Statement. Am J Respir Crit Care Med. 2019;200(8):e70-e88. doi:10.1164/rccm.201908-1590ST.
See Also
pft_interpret() for the downstream interpretation once
acceptable maneuvers have been selected.
Examples
pft_quality(c(3.20, 3.12, 3.10)) # Grade A (n>=3 within 0.150)
pft_quality(c(3.20, 3.12)) # Grade B (n=2 within 0.150)
pft_quality(c(3.20, 3.02)) # Grade C (n>=2 within 0.200)
pft_quality(c(3.20, 2.97)) # Grade D (n>=2 within 0.250)
pft_quality(c(3.20, 2.80)) # Grade E (n>=2 diff > 0.250)
pft_quality(c(3.20)) # Grade E (only 1)
pft_quality(numeric(0)) # Grade F (none)
Grade severity of lung function impairment from a z-score
Description
Assigns one of four severity categories
("normal", "mild", "moderate", "severe") to a z-score per
the Stanojevic et al. ERS/ATS 2022 interpretation standard. The
same grading applies uniformly to spirometry, lung-volume, and
diffusion measures.
Boundary conventions (matching the function's implementation):
| Grade | z-score |
| normal | z >= -1.645 |
| mild | -2.5 <= z < -1.645 |
| moderate | -4 <= z < -2.5 |
| severe | z < -4
|
Usage
pft_severity(zscore)
Arguments
zscore |
Numeric vector of z-scores. |
Value
Character vector the same length as zscore with values
"normal", "mild", "moderate", "severe", or NA.
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. The cut points are taken from the "Severity of lung function impairment" section.
See Also
pft_classify() for the pattern label that severity sits
alongside; pft_gold() for COPD-specific severity from FEV1
percent predicted; pft_interpret() applies this grading to every
z-score column in one call.
Examples
pft_severity(c(0, -1.7, -3, -5))
# -> "normal" "mild" "moderate" "severe"
Severity grading per the Pellegrino 2005 standard
Description
Assigns a five-band severity grade from FEV1 percent predicted, per
the Pellegrino et al. ERJ 2005 standard (the predecessor to the
2022 z-score-based grading implemented by pft_severity()).
Boundary conventions (matching the function's implementation):
| Grade | FEV1 % predicted |
| mild | >= 70% |
| moderate | 60% - 69% |
| moderately severe | 50% - 59% |
| severe | 35% - 49% |
| very severe | < 35%
|
Note that unlike pft_severity(), the 2005 grading has no
"normal" tier – the grades describe the severity of an impairment
that has already been identified, and "normal" lung function is
indicated by the pattern classifier returning "Normal" rather than
by the severity grade itself. Pass only percent-predicted values
from patients with an identified impairment.
Usage
pft_severity_2005(pctpred)
Arguments
pctpred |
Numeric vector of FEV1 percent predicted values
(e.g. the |
Value
Character vector the same length as pctpred with values
"mild", "moderate", "moderately severe", "severe",
"very severe", or NA.
References
Pellegrino R, Viegi G, Brusasco V, et al. Interpretative strategies for lung function tests. Eur Respir J. 2005;26(5):948-968. doi:10.1183/09031936.05.00035205. Severity bands taken from Table 4.
See Also
pft_severity() for the current Stanojevic 2022
z-score-based grading. pft_classify() with standard = "2005"
for the matching 2005-era pattern classifier.
Examples
pft_severity_2005(c(85, 65, 55, 40, 30))
# -> "mild" "moderate" "moderately severe" "severe" "very severe"
Compute spirometry reference values for given demographics
Description
pft_spirometry() computes ATS-compliant upper and lower normal limits
for common spirometry measures including FEV1, FVC, FEV1/FVC, FEF2575, and FEF75.
Usage
pft_spirometry(
data,
year = 2022,
sex = sex,
age = age,
height = height,
race = race
)
Arguments
data |
A data frame containing columns for sex ("M","F"),
race ("AfrAm","NEAsia","SEAsia","Other/mixed", "Caucasian"),
age (in years, in the range 3-95 for FEV1 / FVC / FEV1/FVC and
3-90 for FEF25-75 / FEF75 per the GLI spline tables), and
height (in centimeters).
Rows with If |
year |
The year of GLI published equations. Valid options are
2012 (multi-ethnic, requires a |
sex, age, height, race |
Column references. By default
|
Value
The original data frame with extra columns appended for each
measure. Every output column carries the GLI year as a suffix so
a single result frame can hold multiple equation outputs
side-by-side (fev1_pred_2012, fev1_pred_2022, ...).
-
<measure>_pred_<year>: predicted (median) value. -
<measure>_lln_<year>: lower limit of normal (5th percentile). -
<measure>_uln_<year>: upper limit of normal (95th percentile). If a<measure>_measuredcolumn was supplied indata, two additional columns are emitted: -
<measure>_zscore_<year>: LMS z-score((measured/M)^L - 1) / (L*S). -
<measure>_pctpred_<year>: percent predicted(measured / pred) * 100.
References
Quanjer PH, Stanojevic S, Cole TJ, et al. Multi-ethnic reference values for spirometry for the 3-95-yr age range: the global lung function 2012 equations. Eur Respir J. 2012;40(6):1324-1343. doi:10.1183/09031936.00080312.
Bowerman C, Bhakta NR, Brazzale D, et al. A race-neutral approach to the interpretation of lung function measurements. Am J Respir Crit Care Med. 2023;207(6):768-774. doi:10.1164/rccm.202205-0963OC.
See Also
pft_volumes() and pft_diffusion() for the analogous
reference-value functions for lung volumes and diffusion capacity.
pft_classify() consumes the LLN columns produced here to assign
ATS interpretive patterns. pft_interpret() is the one-call
wrapper that combines spirometry, volumes, diffusion, and all
downstream interpretation primitives.
Examples
data <- data.frame(sex=c("M","F"),
age=c(30.1,5.1),
height=c(178,50),
race=c("SEAsia","NEAsia"))
pft_spirometry(data)
Classify lung-volume sub-pattern per Stanojevic 2022 Figure 10
Description
Differentiates the six lung-volume sub-patterns described in the
2022 ERS/ATS interpretive standard: Normal lung volumes,
Large lungs, Hyperinflation, Simple restriction,
Complex restriction, and Mixed disorder. These are the
patterns that pft_classify() collapses into "Restricted",
"Mixed", and "Obstructed" / "Normal" – this function recovers the
finer-grained labels when lung-volume ratios (FRC/TLC and / or
RV/TLC) are available.
Typically called via pft_interpret() as part of the one-call
workflow; exported for callers who want to apply the sub-pattern
classifier to pre-computed columns directly.
Usage
pft_volume_subpattern(
data,
year = 2022,
tlc = tlc,
tlc_lln = tlc_lln,
tlc_uln = tlc_uln,
fev1fvc = fev1fvc,
fev1fvc_lln = NULL,
rv_tlc = rv_tlc,
rv_tlc_uln = rv_tlc_uln,
frc_tlc = NULL,
frc_tlc_uln = NULL
)
Arguments
data |
A data frame containing at minimum:
Optional columns to refine the elevated-volumes branch:
|
year |
GLI year suffix used when looking up the spirometry
FEV1/FVC LLN column. Defaults to |
tlc, tlc_lln, tlc_uln, fev1fvc, fev1fvc_lln, rv_tlc, rv_tlc_uln |
Column references for the seven required inputs. Defaults are the
canonical names ( |
frc_tlc, frc_tlc_uln |
Column references for the optional FRC/TLC
pair. Default |
Details
Implements the decision tree in Figure 10 of Stanojevic et al. ERJ 2022 (p. 21) verbatim:
TLC < 5th percentile (LLN)?
YES -> Restriction:
FRC/TLC OR RV/TLC > 95th percentile (ULN)?
YES:
FEV1/FVC < 5th percentile?
YES -> "Mixed disorder"
NO -> "Complex restriction"
NO -> "Simple restriction"
NO:
TLC > 95th percentile?
YES (possible hyperinflation):
FRC/TLC OR RV/TLC > 95th percentile?
YES -> "Hyperinflation"
NO -> "Large lungs"
NO:
FRC/TLC OR RV/TLC > 95th percentile?
YES -> "Hyperinflation"
NO -> "Normal lung volumes"
RV/TLC reference ranges are produced by pft_volumes() (per
Hall 2021 Table 3 row for RV/TLC). FRC/TLC is not fitted in the
Hall 2021 standard; if the caller has FRC/TLC and its ULN
available, supply them as columns frc_tlc / frc_tlc_uln to
refine the OR-condition. When absent (the typical case), only
RV/TLC is consulted – the function degrades gracefully.
Value
The input data with a new volume_subpattern character
column appended. Values are one of "Normal lung volumes",
"Large lungs", "Hyperinflation", "Simple restriction",
"Complex restriction", "Mixed disorder", or NA_character_
if any required column is NA for that row.
Column-name overrides
Each column-reference argument accepts three forms:
a bare column name –
tlc = my_tlca string –
tlc = "my_tlc"an injected value –
tlc = !!my_varwheremy_var <- "my_tlc"
Defaults are the canonical pft column names, so callers whose data
already follows the convention pass no extra arguments. The optional
FRC/TLC pair (frc_tlc, frc_tlc_uln) defaults to NULL to enable
canonical-name auto-pickup; pass explicit column references to
override.
References
Stanojevic S, Kaminsky DA, Miller MR, et al. ERS/ATS technical standard on interpretive strategies for routine lung function tests. Eur Respir J. 2022;60(1):2101499. doi:10.1183/13993003.01499-2021. Lung-volume sub-patterns defined in Figure 10 (p. 21) and Table 7 (p. 22).
See Also
pft_classify() for the five-band airflow / restriction
classification; pft_volumes() to obtain rv_tlc / rv_tlc_uln
per Hall 2021; pft_interpret() composes both classifications
when the input columns are present.
Examples
# Mixed disorder: TLC < LLN, RV/TLC > ULN, FEV1/FVC < LLN.
data.frame(
tlc = 4.0, tlc_lln = 5.0, tlc_uln = 7.0,
fev1fvc = 0.55, fev1fvc_lln_2022 = 0.70,
rv_tlc = 0.55, rv_tlc_uln = 0.45
) |> pft_volume_subpattern()
# Simple restriction: TLC < LLN, both ratios normal.
data.frame(
tlc = 4.0, tlc_lln = 5.0, tlc_uln = 7.0,
fev1fvc = 0.80, fev1fvc_lln_2022 = 0.70,
rv_tlc = 0.30, rv_tlc_uln = 0.45
) |> pft_volume_subpattern()
Compute lung volume reference values for given demographics
Description
pft_volumes() computes ATS-compliant upper and lower normal limits
for lung volume measures including FRC, TLC, RV, ERV, IC, and VC.
Usage
pft_volumes(data, sex = sex, age = age, height = height)
Arguments
data |
A data frame containing columns for sex ("M","F"),
age (in years, in the range 5-80 per the GLI 2021 spline tables)
and height (in centimeters). If |
sex, age, height |
Column references. By default |
Value
The original data frame with extra columns appended for each measure:
-
<measure>_pred: predicted (median) value. -
<measure>_lln: lower limit of normal (5th percentile). -
<measure>_uln: upper limit of normal (95th percentile). If a<measure>_measuredcolumn was supplied indata, two additional columns are emitted: -
<measure>_zscore: LMS z-score((measured/M)^L - 1) / (L*S). -
<measure>_pctpred: percent predicted(measured / pred) * 100.
References
Hall GL, Filipow N, Ruppel G, et al. Official ERS technical standard: Global Lung Function Initiative reference values for static lung volumes in individuals of European ancestry. Eur Respir J. 2021;57(3):2000289. doi:10.1183/13993003.00289-2020.
See Also
pft_spirometry() and pft_diffusion() for the analogous
reference-value functions. pft_classify() uses TLC and its LLN
(produced by this function) to identify restrictive impairments.
pft_interpret() composes all three reference functions in one
call.
Examples
data <- data.frame(sex=c("M","F"),
age=c(30,5.1),
height=c(178,50))
pft_volumes(data)
Objects exported from other packages
Description
These objects are imported from other packages. Follow the links below to see their documentation.
- tibble