library(tidyverse)
library(PKNCA)
data(Theoph)
theoph_conc <- as_tibble(Theoph) %>%
transmute(ID = Subject, TIME = Time, CONC = conc)
theoph_dose <- as_tibble(Theoph) %>%
distinct(Subject, Dose) %>%
transmute(ID = Subject, TIME = 0, DOSE = Dose)
conc_obj <- PKNCAconc(CONC ~ TIME | ID, data = theoph_conc)
dose_obj <- PKNCAdose(DOSE ~ TIME | ID, data = theoph_dose)AUCinf vs Partial AUC: Choosing the Right Interval in NCA
Big idea: AUC is defined over an interval. Choosing 0–Inf versus 0–T is not cosmetic — it changes how much extrapolation you accept.
Learning Objectives
By the end of this lesson, you will be able to:
- Explain the computational difference between AUCinf and partial AUC.
- Define multiple intervals in
PKNCA. - Compare AUC0–T (e.g., 0–24) with AUC0–Inf.
- Interpret extrapolation fraction in the context of interval choice.
Conceptual Bridge
In a previous lesson we evaluated whether the terminal phase is reliable enough to estimate \(\lambda_z\) and half-life.
Here we examine how that decision affects the exposure metric you report — specifically the choice between AUC\(_{0-\infty}\) and partial AUC.
Key Ideas
- AUC0–Tlast (partial AUC) integrates only observed data.
- AUC0–Inf integrates observed data plus extrapolated tail area.
- Extrapolation depends on the estimated terminal slope (\(\lambda_z\)).
- If terminal slope is unstable, AUCinf is unstable.
- Partial AUC is often more robust when sampling is limited.
Setup: Run NCA on Theoph
Step 1: Define the Intervals You Want
We will compute an observed AUC-to-last metric and AUCinf in the same run.
intervals_df <- data.frame(
start = 0,
end = Inf,
auclast = TRUE,
aucinf.obs = TRUE
)
nca_data <- PKNCAdata(conc_obj, dose_obj, intervals = intervals_df)
results_obj <- pk.nca(nca_data)
raw_df <- as.data.frame(results_obj)
sort(unique(raw_df$PPTESTCD)) [1] "adj.r.squared" "aucinf.obs" "auclast"
[4] "clast.obs" "clast.pred" "half.life"
[7] "lambda.z" "lambda.z.n.points" "lambda.z.time.first"
[10] "lambda.z.time.last" "r.squared" "span.ratio"
[13] "tlast" "tmax"
Step 2: Extract AUC Outputs
We extract the two AUC metrics returned by PKNCA:
auclastaucinf.obs
auc_tbl <- raw_df %>%
filter(PPTESTCD %in% c("auclast", "aucinf.obs")) %>%
select(ID, PPTESTCD, PPORRES) %>%
pivot_wider(names_from = PPTESTCD, values_from = PPORRES)
auc_tbl %>%
select(ID, auclast, aucinf.obs) %>%
head()# A tibble: 6 × 3
ID auclast aucinf.obs
<ord> <dbl> <dbl>
1 6 71.7 82.2
2 7 88.0 101.
3 8 86.8 102.
4 11 77.9 86.9
5 3 95.9 106.
6 2 88.7 97.4
Step 3: Compute Extrapolated Fraction
\[ \text{Extrapolated Fraction} = \frac{AUC_{0-\infty} - AUC_{0-tlast}}{AUC_{0-\infty}} \]
auc_tbl <- auc_tbl %>%
mutate(
extrap_fraction = (aucinf.obs - auclast) / aucinf.obs
)
auc_tbl %>%
select(ID, extrap_fraction) %>%
head()# A tibble: 6 × 2
ID extrap_fraction
<ord> <dbl>
1 6 0.128
2 7 0.129
3 8 0.150
4 11 0.104
5 3 0.0966
6 2 0.0888
Interpretation
- If extrapolated fraction is small (e.g., <20%), AUCinf is close to observed exposure.
- If extrapolated fraction is large, AUCinf relies heavily on the terminal slope.
- In sparse sampling, AUCinf may be less stable than partial AUC.
Partial AUC avoids extrapolation entirely.
When Partial AUC Is Preferable
- Fixed dosing interval (e.g., AUC0–24)
- Sparse terminal sampling
- Unstable lambda_z / unreliable half-life
- When your decision is about observed exposure within a window
Computational Takeaway
In PKNCA, interval choice is controlled in intervals_df.
Changing:
end = Infto something like:
end = 24changes the exposure definition you compute.
Strategies
- Compute both AUC0–T (or AUC0–Tlast) and AUC0–Inf during exploratory work.
- Examine extrapolated fraction before reporting AUCinf.
- Document interval definitions in your reporting layer.
- Keep interval choice consistent across groups.
Practice Problems
- Executable: Compute AUC0–12 by setting
end = 12and requestingauclast = TRUE. - Executable: Identify subjects with extrapolated fraction > 0.25.
- Conceptual: Why might partial AUC be more stable in sparse designs?
1. AUC0–12:
intervals_0_12 <- data.frame(
start = 0,
end = 12,
auclast = TRUE
)
nca_0_12 <- PKNCAdata(conc_obj, dose_obj, intervals = intervals_0_12)
as.data.frame(pk.nca(nca_0_12)) %>%
head()# A tibble: 6 × 6
ID start end PPTESTCD PPORRES exclude
<ord> <dbl> <dbl> <chr> <dbl> <chr>
1 6 0 12 auclast 43.0 <NA>
2 7 0 12 auclast 50.1 <NA>
3 8 0 12 auclast 51.5 <NA>
4 11 0 12 auclast 49.0 <NA>
5 3 0 12 auclast 57.1 <NA>
6 2 0 12 auclast 67.2 <NA>
2. Extrapolation > 25%:
auc_tbl %>%
filter(!is.na(extrap_fraction), extrap_fraction > 0.25)# A tibble: 1 × 4
ID auclast aucinf.obs extrap_fraction
<ord> <dbl> <dbl> <dbl>
1 1 147. 215. 0.315
3. Conceptual answer:
Partial AUC does not depend on terminal slope estimation. Sparse terminal data can destabilize \(\lambda_z\) and inflate extrapolated area, making AUCinf less reliable.
Summary
AUC depends on the interval you define.
- AUC0–Tlast uses only observed data.
- AUC0–Inf adds extrapolated tail area.
- Extrapolation depends on terminal slope quality.
- In PKNCA, interval choice is controlled explicitly in
intervals_df.
- Start by checking available outputs using
unique(raw_df$PPTESTCD). - Extrapolated fraction is a practical reliability flag for AUCinf.
- Partial AUC is often more robust when terminal data are weak.
- Document interval definitions in every report.