derive_terminal_phase.RdEstimates the terminal elimination rate constant \(\lambda_z\) for each profile by log-linear regression, and derives from it the terminal half-life, the area under the curve extrapolated to infinity, and the percentage of that area that was extrapolated rather than observed.
Concentration-time data: one record per subject, analyte and
timepoint. The output of make_adpc() is a valid input.
Character vector of grouping variables. One output record is produced per combination.
Name of the concentration column in pc.
Name of the time column in pc, in hours since first dose.
AUC method for the observed part: "linear" (default) or
"lin_up_log_down". See derive_exposure_metrics().
Minimum number of points in the terminal regression. Must be at least 3, because an adjusted R-squared needs a residual degree of freedom.
Percentage of AUCIFO above which AUCPEFL is
"Y". Default 20.
Adjusted R-squared tolerance for the best-fit tie-break.
An eradam_terminal object: a tibble::tibble with one row per
by group.
This is the non-compartmental half of an exposure analysis that
derive_exposure_metrics() deliberately does not do: that function computes
only what can be read off the observed points (CMAX, TMAX, CMIN,
CTROUGH, AUCLST), and every parameter here needs a fitted model.
The window is selected by the best fit rule used by non-compartmental analysis software:
Candidate points are the quantifiable observations (conc > 0) at times
strictly after TMAX. TMAX itself and everything earlier is
excluded, so the absorption phase cannot contaminate the slope.
Every terminal window of min_points (default 3, the conventional
minimum) up to all candidate points is regressed as
\(\ln C = a + b\,t\).
Among the windows whose adjusted R-squared is within tol (default
0.0001) of the best value, the one using the most points is taken.
Comparing adjusted rather than raw R-squared is what stops the rule from
always preferring the shortest window.
\(\lambda_z = -b\). If the fitted slope is not negative there is no
elimination phase to describe and the result is NA.
The fit is reported with the estimate, never on its own: LAMZNPT (points
used), LAMZLL/LAMZUL (the time window), R2 and R2ADJ. A reviewer can
then judge the fit rather than trust it. When no acceptable fit exists,
LAMZ and everything derived from it are NA and LAMZNRS states why in
words — there is no silently bad number.
Let CLST be the last positive concentration, at time TLST, and
CLSTP \(= \exp(a + b\,TLST)\) its value predicted by the terminal fit.
AUCLST — observed area to TLST, by the same trapezoidal method as
derive_exposure_metrics().
AUCIFO \(= AUCLST + CLST / \lambda_z\) (observed variant).
AUCIFP \(= AUCLST + CLSTP / \lambda_z\) (predicted variant). Both are
returned; neither is "the" answer, and a study should state which it uses.
AUCPEO, AUCPEP — percentage of AUCIFO / AUCIFP contributed by the
extrapolated tail, \(100 (AUCIF - AUCLST) / AUCIF\).
AUCPEFL — "Y" when AUCPEO exceeds max_pct_extrap (default 20, the
conventional acceptance threshold), otherwise "N". The value is still
returned; the flag says do not rely on it.
LAMZ, LAMZHL, LAMZLL, LAMZUL, LAMZNPT, R2, R2ADJ, AUCIFO,
AUCIFP, AUCPEO, AUCPEP, CLST, TLST and AUCLST are CDISC
PPTESTCD parameter codes, used here with their CDISC meanings. CLSTP,
AUCPEFL and LAMZNRS are this package's names, as is the wide
one-row-per-profile layout — CDISC would carry these as one record per
parameter in PP/ADPP.
The best-fit selection rule, the exclusion of TMAX, the three-point
minimum and the 20% extrapolation threshold are the accepted pharmacometric
conventions, not this package's inventions. The tol = 1e-4 tie-break
constant is the value non-compartmental analysis software uses.
AUCLST here runs to the last positive concentration, which is the
non-compartmental convention. derive_exposure_metrics() runs its AUCLST
over every non-missing record. The two agree unless a profile has trailing
zero concentrations — which it will if you ran make_adpc() with
blq = "zero" — and then this one is the standard value and the other
includes the run-down to zero.
Everything in a by group is treated as one profile. On a multiple-dose
study that is usually not what you want: the shipped fixture doses at 0 h and
24 h, so TMAX for 10 of its 24 subjects falls after the second dose and
only two terminal points remain — those 10 correctly return NA with the
reason rather than a slope fitted through two points. Subset to the dosing
interval you mean before calling.
Not implemented: steady-state parameters (AUCTAU, CAVG, CLSS,
accumulation and fluctuation), clearance and volume (CL, CLF, VZ,
VZF, MRT), moment curves (AUMC, VSS), sparse-sampling and
Bailer-type variance estimation, and any manual override of the LAMZ
window — the best-fit rule chooses it or nothing does, which a regulatory
NCA usually needs to be able to overrule. If you need those, run the profile
through a validated NCA package; this is an open implementation of published
rules, not validated software.
| Variable | Meaning | Source |
USUBJID | Unique subject identifier | pc (grouping variable) |
PARAMCD | Analyte code | pc (grouping variable) |
NOBS | Number of usable observations in the profile | Derived |
TLST | Time of the last positive (quantifiable) concentration | Derived from time |
CLST | Last positive (quantifiable) concentration, observed | Derived from conc |
AUCLST | Area under the curve to TLST, by the trapezoidal method | Derived |
CLSTP | Concentration at TLST predicted by the terminal fit | Derived from the lambda z regression |
LAMZ | Terminal elimination rate constant (1/time); NA when no acceptable fit | Derived by log-linear regression |
LAMZHL | Terminal half-life, log(2) / LAMZ | Derived |
LAMZNPT | Number of points used in the terminal regression | Derived |
LAMZLL | Lower time limit of the terminal regression window | Derived |
LAMZUL | Upper time limit of the terminal regression window | Derived |
R2 | R-squared of the terminal regression | Derived |
R2ADJ | Adjusted R-squared of the terminal regression (the value the window was chosen on) | Derived |
AUCIFO | AUC extrapolated to infinity using the observed CLST | Derived |
AUCIFP | AUC extrapolated to infinity using the predicted CLSTP | Derived |
AUCPEO | Percentage of AUCIFO that was extrapolated | Derived |
AUCPEP | Percentage of AUCIFP that was extrapolated | Derived |
AUCPEFL | "Y" when AUCPEO exceeds max_pct_extrap (default 20%) | Derived |
LAMZNRS | Reason LAMZ is NA, in words; NA when LAMZ was estimated | Derived |
derive_exposure_metrics() for the observed metrics and
derive_partial_auc() for an area over a stated window.
# a synthetic mono-exponential decay: C = 100 * exp(-0.1 * t)
t <- c(0, 1, 2, 4, 8, 12, 24)
mono <- data.frame(
USUBJID = "X-001", PARAMCD = "DRUGX",
AFRLT = t, AVAL = 100 * exp(-0.1 * t)
)
tp <- derive_terminal_phase(mono)
tp[, c("LAMZ", "LAMZHL", "LAMZNPT", "R2ADJ", "AUCIFO", "AUCPEO")]
#> # A tibble: 1 × 6
#> LAMZ LAMZHL LAMZNPT R2ADJ AUCIFO AUCPEO
#> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
#> 1 0.1 6.93 6 1 1030. 8.81
# lambda z recovers 0.1, half-life log(2) / 0.1, AUCIFO the analytic 100 / 0.1
# a profile with too few points after TMAX yields NA and says why
short <- data.frame(
USUBJID = "X-002", PARAMCD = "DRUGX",
AFRLT = c(0, 1, 2), AVAL = c(1, 10, 5)
)
derive_terminal_phase(short)$LAMZNRS
#> [1] "Only 1 quantifiable point after TMAX (1); 3 required."
# on the shipped fixtures
pc <- eradam_example("pc")
derive_terminal_phase(pc[pc$PARAMCD == "DRUGX", ])
#>
#> ── eradam terminal-phase parameters ────────────────────────────────────────────
#> ℹ 24 profile(s) | AUC method: linear | min points: 3
#> ℹ Lambda z estimated for 14/24 profile(s)
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (27.993); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28.036); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (27.951); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28.06); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28.022); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28.05); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28.029); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (27.97); 3 required.
#> ! 1 profile(s): Only 2 quantifiable points after TMAX (28.014); 3 required.
#> ℹ LAMZHL: median 6.519 (range 4.251 to 9.53)
#> ✔ No profile extrapolates more than 20% of AUCIFO
#> # A tibble: 24 × 20
#> USUBJID PARAMCD NOBS TLST CLST AUCLST CLSTP LAMZ LAMZHL LAMZNPT LAMZLL
#> <chr> <chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <int> <dbl>
#> 1 ERADAM0… DRUGX 11 48.0 15.6 6619. 15.7 0.148 4.69 3 28.0
#> 2 ERADAM0… DRUGX 11 48.0 64.6 11468. 63.2 0.101 6.85 3 28.1
#> 3 ERADAM0… DRUGX 11 48.0 89.9 11919. NA NA NA NA NA
#> 4 ERADAM0… DRUGX 11 48.1 53.7 10329. NA NA NA NA NA
#> 5 ERADAM0… DRUGX 11 48.0 30.8 6868. 31.4 0.114 6.09 3 28.0
#> 6 ERADAM0… DRUGX 11 48.0 30.6 6645. NA NA NA NA NA
#> 7 ERADAM0… DRUGX 11 48.0 41.9 8033. NA NA NA NA NA
#> 8 ERADAM0… DRUGX 11 48.1 82.3 12978. 83.2 0.0898 7.72 3 28.0
#> 9 ERADAM0… DRUGX 11 48.0 92.5 19621. 93.9 0.108 6.44 3 28.0
#> 10 ERADAM0… DRUGX 11 48.0 252. 30823. 259. 0.0727 9.53 3 28.0
#> # ℹ 14 more rows
#> # ℹ 9 more variables: LAMZUL <dbl>, R2 <dbl>, R2ADJ <dbl>, AUCIFO <dbl>,
#> # AUCIFP <dbl>, AUCPEO <dbl>, AUCPEP <dbl>, AUCPEFL <chr>, LAMZNRS <chr>