Area under the concentration-time curve between two caller-stated times — AUC[0, 24], AUC over a dosing interval, or any other window a protocol asks for. The SAS idiom this replaces is a PROC EXPAND / RETAIN trapezoid loop over a WHERE-clipped copy of the concentration dataset, with the window edges hand-interpolated before the loop.

derive_partial_auc(
  pc,
  start,
  end,
  by = c("USUBJID", "PARAMCD"),
  conc = "AVAL",
  time = "AFRLT",
  method = c("linear", "lin_up_log_down")
)

Arguments

pc

Concentration-time data: one record per subject, analyte and timepoint. The output of make_adpc() is a valid input.

start, end

Window edges, in the units of time. start must be less than end.

by

Character vector of grouping variables. One output record is produced per combination.

conc

Name of the concentration column in pc.

time

Name of the time column in pc, in hours since first dose.

method

AUC method: "linear" (default) or "lin_up_log_down". Also selects the edge interpolation rule, as described above.

Value

An eradam_partial object: a tibble::tibble with one row per by group.

The edge rule

This is where implementations silently disagree, so it is stated rather than assumed. When start or end falls between two observed timepoints, a concentration is interpolated at that time and used as the endpoint of the first (or last) trapezoid:

  • method = "linear" — linear interpolation between the two bracketing observations.

  • method = "lin_up_log_down" — logarithmic interpolation when the bracketing segment is descending and both bracketing concentrations are strictly positive, linear otherwise. This matches the trapezoid rule actually being applied on that segment.

When start or end coincides exactly with an observed time, the observed concentration is used and nothing is interpolated; INTRPFL reports which happened. AUCINT over the full observed window is therefore identical to AUCLST from derive_exposure_metrics() with the same method.

The window must lie inside the observed range of each profile. If start is before the first observation or end is after the last, the result is NA with the reason in AUCINTRS — this function never back-extrapolates to time zero and never forward-extrapolates with \(\lambda_z\). Both of those are real conventions used elsewhere, and picking one silently is exactly how two "AUC0-24" columns end up disagreeing. For the forward tail, use derive_terminal_phase(), which extrapolates explicitly and reports how much it extrapolated.

In practice this bites at the pre-dose sample: if the 0 h result is below the limit of quantification and still missing, the profile's first usable observation is the first post-dose sample and AUC[0, t] refuses. Run make_adpc() first so the BLQ policy has given that record a value — the policy is then visible in the delivered dataset instead of hidden inside this function.

Conventions

AUCINT is the CDISC PPTESTCD code for an area between two times. AUCINTLL, AUCINTUL, NOBSINT, INTRPFL and AUCINTRS are this package's names, as is the wide one-row-per-profile layout. The interpolation rules above are the ones non-compartmental analysis software uses; the refusal to extrapolate past the observed range is this package's choice.

Limits

One window per call. For several windows, call it once per window and rbind() the results — AUCINTLL and AUCINTUL identify each. Steady-state AUCTAU is not a separate parameter here: pass the dosing interval as start and end on a steady-state profile and you get the same number under the name AUCINT, but none of the other steady-state parameters (CAVG, accumulation ratio, fluctuation) are derived.

Output structure

VariableMeaningSource
USUBJIDUnique subject identifierpc (grouping variable)
PARAMCDAnalyte codepc (grouping variable)
AUCINTLLLower edge of the requested windowArgument start
AUCINTULUpper edge of the requested windowArgument end
AUCINTArea under the curve between AUCINTLL and AUCINTULDerived
NOBSINTNumber of points used, counting interpolated window edgesDerived
INTRPFL"Y" when a window edge had to be interpolated between observationsDerived
AUCINTRSReason AUCINT is NA, in words; NA when it was derivedDerived

Examples

# 0, 10, 20, 10 at 0, 1, 2, 3 h — AUC over the whole window is 35
curve <- data.frame(
  USUBJID = "X-001", PARAMCD = "DRUGX",
  AFRLT = c(0, 1, 2, 3), AVAL = c(0, 10, 20, 10)
)
derive_partial_auc(curve, 0, 3)$AUCINT
#> [1] 35

# a window with an interpolated edge: at 1.5 h the linear rule gives 15
derive_partial_auc(curve, 1.5, 3)[, c("AUCINT", "NOBSINT", "INTRPFL")]
#> # A tibble: 1 × 3
#>   AUCINT NOBSINT INTRPFL
#>    <dbl>   <int> <chr>  
#> 1   23.8       3 Y      

# AUC[0, 24] on the shipped fixtures. The raw 0 h sample is below the limit
# of quantification, so run make_adpc() first to give it a value — otherwise
# the window starts before the first usable observation and the answer is
# NA with the reason, which is the point of the rule.
pc <- eradam_example("pc")
derive_partial_auc(pc[pc$PARAMCD == "DRUGX", ], 0, 24)$AUCINTRS[1]
#> [1] "Window [0, 24] is not inside the observed range [0.58, 48.006]; no extrapolation is done."

adpc <- make_adpc(pc, eradam_example("adsl"), eradam_example("ex"), blq = "half")
derive_partial_auc(adpc[adpc$PARAMCD == "DRUGX", ], 0, 24)
#> 
#> ── eradam partial AUC ──────────────────────────────────────────────────────────
#>  24 profile(s) | window [0, 24] | AUC method: linear
#>  AUCINT derived for 24/24 profile(s)
#>  AUCINT: median 10110 (range 3147 to 24010)
#>  24 profile(s) needed an interpolated window edge
#> # A tibble: 24 × 8
#>    USUBJID      PARAMCD AUCINTLL AUCINTUL AUCINT NOBSINT INTRPFL AUCINTRS
#>    <chr>        <chr>      <dbl>    <dbl>  <dbl>   <int> <chr>   <chr>   
#>  1 ERADAM01-001 DRUGX          0       24  3304.       9 Y       NA      
#>  2 ERADAM01-002 DRUGX          0       24  5514.       9 Y       NA      
#>  3 ERADAM01-003 DRUGX          0       24  5515.       9 Y       NA      
#>  4 ERADAM01-004 DRUGX          0       24  4997.       9 Y       NA      
#>  5 ERADAM01-005 DRUGX          0       24  3147.       9 Y       NA      
#>  6 ERADAM01-006 DRUGX          0       24  3164.       9 Y       NA      
#>  7 ERADAM01-007 DRUGX          0       24  3788.       9 Y       NA      
#>  8 ERADAM01-008 DRUGX          0       24  6307.       9 Y       NA      
#>  9 ERADAM01-009 DRUGX          0       24  9743.       9 Y       NA      
#> 10 ERADAM01-010 DRUGX          0       24 14396.       9 Y       NA      
#> # ℹ 14 more rows