Input data format

The reference functions in pft (pft_spirometry(), pft_volumes(), pft_diffusion(), and the one-call workflow pft_interpret()) all take a data frame and append reference columns to it. This article documents exactly which columns each function expects, which are optional, and how to point pft at columns whose names don’t match the canonical ones.

Required vs. optional columns

Three categories of column drive the reference functions:

Required – demographics that must be present, or the function errors:

Optional measured<measure>_measured columns whose presence unlocks z-score and percent-predicted outputs for that measure. Missing these is silent; the function simply emits fewer output columns. Recognised measures by function:

Optional BDR – (pft_interpret() only) <measure>_pre and <measure>_post columns for fev1, fvc, or fev1fvc. When present, bronchodilator-response columns are appended.

Units and types

The canonical types and units are:

Column Type Allowed values / units
sex character "M" or "F". Common variants ("male", "Female", "m", …) are auto-normalised with a warning.
age numeric Years (decimal allowed).
height numeric Centimetres.
race character One of "Caucasian", "AfrAm", "NEAsia", "SEAsia", "Other/mixed". Common synonyms are auto-normalised. (GLI 2012 only.)
fev1_measured, fvc_measured, etc. (spirometry) numeric Litres for volumes; L/s for flows; dimensionless for FEV1/FVC.
frc_measured, tlc_measured, … (volumes) numeric Litres. rv_tlc_measured is dimensionless.
dlco_measured / tlco_measured / kco_* / va_measured (diffusion) numeric Diffusion measures in the unit system requested via SI.units.
<measure>_pre, <measure>_post (BDR) numeric Same units as <measure>_measured.

See the Glossary for definitions of every measure abbreviation.

Using non-canonical column names

If your data frame uses different column names for the demographics, all reference functions accept sex, age, height, and (where applicable) race overrides. Three forms are accepted: a bare column name (the usual tidyverse style), a string, or an injection from a variable:

patient <- data.frame(
  Sex      = "M",
  Age_y    = 45,
  Ht_cm    = 178,
  Ancestry = "Caucasian"
)

# Bare names (tidyverse-style)
pft_spirometry(patient,
               sex    = Sex,
               age    = Age_y,
               height = Ht_cm,
               race   = Ancestry)
#> # A tibble: 1 × 13
#>   Sex   Age_y Ht_cm Ancestry  fev1_pred_2022 fev1_lln_2022 fev1_uln_2022
#>   <chr> <dbl> <dbl> <chr>              <dbl>         <dbl>         <dbl>
#> 1 M        45   178 Caucasian           3.87          2.94          4.75
#> # ℹ 6 more variables: fvc_pred_2022 <dbl>, fvc_lln_2022 <dbl>,
#> #   fvc_uln_2022 <dbl>, fev1fvc_pred_2022 <dbl>, fev1fvc_lln_2022 <dbl>,
#> #   fev1fvc_uln_2022 <dbl>
# Strings -- equivalent
pft_spirometry(patient,
               sex    = "Sex",
               age    = "Age_y",
               height = "Ht_cm",
               race   = "Ancestry")
#> # A tibble: 1 × 13
#>   Sex   Age_y Ht_cm Ancestry  fev1_pred_2022 fev1_lln_2022 fev1_uln_2022
#>   <chr> <dbl> <dbl> <chr>              <dbl>         <dbl>         <dbl>
#> 1 M        45   178 Caucasian           3.87          2.94          4.75
#> # ℹ 6 more variables: fvc_pred_2022 <dbl>, fvc_lln_2022 <dbl>,
#> #   fvc_uln_2022 <dbl>, fev1fvc_pred_2022 <dbl>, fev1fvc_lln_2022 <dbl>,
#> #   fev1fvc_uln_2022 <dbl>
# Injection from a variable, e.g. driven by a config
sex_col <- "Sex"
pft_spirometry(patient, sex = !!sex_col,
               age    = Age_y,
               height = Ht_cm,
               race   = Ancestry)
#> # A tibble: 1 × 13
#>   Sex   Age_y Ht_cm Ancestry  fev1_pred_2022 fev1_lln_2022 fev1_uln_2022
#>   <chr> <dbl> <dbl> <chr>              <dbl>         <dbl>         <dbl>
#> 1 M        45   178 Caucasian           3.87          2.94          4.75
#> # ℹ 6 more variables: fvc_pred_2022 <dbl>, fvc_lln_2022 <dbl>,
#> #   fvc_uln_2022 <dbl>, fev1fvc_pred_2022 <dbl>, fev1fvc_lln_2022 <dbl>,
#> #   fev1fvc_uln_2022 <dbl>

The user’s original column names are preserved in the output (no renaming to canonical). Sex and race values are normalised in place, so e.g. "male" becomes "M" in the original Sex column.

The _measured, _pre, and _post columns are not overridable – they are looked up by name. If your data uses different names, rename them before calling pft:

library(dplyr)
patient %>%
  rename(fev1_measured = FEV1_L,
         fvc_measured  = FVC_L) %>%
  pft_spirometry(year = 2022)

Common errors

required column(s) missing from input: 'race' – you called pft_spirometry(d, year = 2012) without a race column. Either supply one (canonical levels: "Caucasian", "AfrAm", "NEAsia", "SEAsia", "Other/mixed") or call pft_spirometry(d, year = 2022) for the race-neutral equations.

Warning: pft input normalization: ... – one or more sex or race values were normalised (e.g. "male""M") or set to NA because they didn’t match any known canonical value. The warning is consolidated to one message per call and lists the offending values so you can locate the affected rows.

year = 2012 running but all outputs NA – check whether the race column contains values outside the five GLI 2012 categories. Unknown values are set to NA, which propagates through the reference equations.