Lambda-z Diagnostics

Diagnostic tools for evaluating the quality of the terminal elimination rate constant (lambda-z) fit and identifying influential or outlier observations.

Diagnostics

NCA.lambdaz_diagnostics — Function
Experimental

This endpoint is experimental — outlier criteria, default thresholds, and return type may change without a deprecation cycle.

Per-point influence diagnostics for the λz terminal elimination regression.

Computes how each timepoint in the regression window affects the λz estimate, and flags statistical outliers. Depends on lambdaz_fit.

Known limitations

  • Diagnostics only see points already inside the λz regression window. The automatic window selection grows from the last 3 points and stops when adjR² worsens, so an outlier just outside the window is invisible to outlier detection. If you suspect a point near the boundary, set lambdaz_mask manually to widen the window before computing diagnostics.

Returns a LambdazDiagnostics struct containing residuals, leverage, Cook's distance, DFBETA, leave-one-out estimates, and outlier flags.

Outlier criteria

Points are flagged when any active criterion is exceeded (OR logic). The outlier_criteria field records which criteria triggered for each point.

Studentized residuals (always active)

Externally studentized residuals follow a t-distribution under H₀. A Bonferroni correction controls family-wise error rate across all n points. alpha=0.05 is standard; lower values reduce false positives but may miss real outliers. Requires n ≥ 4 (with n = 4, power is very low).

Cook's distance (cooks_threshold)

Measures each point's overall influence on both regression coefficients. Common thresholds: 4/n (conservative, flags more points) or 1.0 (permissive). Use when concerned about single points dominating the fit.

Leverage (leverage_threshold)

Hat matrix diagonal — measures how extreme each point's x-position (timepoint) is relative to the mean. Standard threshold: 2p/n = 4/n for simple linear regression. High leverage alone isn't problematic; it only matters when combined with a large residual (which Cook's distance captures).

DFBETA (dfbeta_threshold)

Fractional change in λz when each point is removed. Most directly PK-relevant: 0.2 flags points whose removal changes λz by more than 20%. Useful for identifying timepoints that disproportionately determine the half-life estimate.

Quality metrics

These are included for assessment but are not used for outlier flagging:

  • SE / CV%: standard error and coefficient of variation of λz (in lambdaz_fit)
  • PRESS: predicted residual error sum of squares; lower = better predictive fit

Practical guidance

  • Defaults (studentized residuals only) are a good starting point.
  • Multi-criteria: add cooks_threshold and/or dfbeta_threshold for stricter screening.
  • n = 3: studentized residuals, DFBETA, and the leave-one-out λz and t½ are NaN, since the studentized test has n − 3 = 0 degrees of freedom. Only leverage and Cook's distance are computed.
  • n = 4: studentized residuals have very low power; consider DFBETA instead.
  • n ≥ 5: all criteria produce meaningful results.
  • Use format_diagnostics to display results and exclude_lambdaz to act on flagged outliers.

Keyword arguments

  • alpha=0.05: significance level for Bonferroni-corrected studentized residual test
  • cooks_threshold=nothing: Cook's distance cutoff (e.g. 1.0 or 4/n); nothing = inactive
  • leverage_threshold=nothing: hat matrix diagonal cutoff (e.g. 4/n); nothing = inactive
  • dfbeta_threshold=nothing: max fractional change in λz (e.g. 0.2 for 20%); nothing = inactive

Example

# Basic usage — studentized residuals only
report = run_nca(pop, [:lambdaz_fit, :lambdaz_diagnostics])

# Multi-criteria — also flag by Cook's distance and DFBETA
report = run_nca(pop, [:lambdaz_fit,
  :lambdaz_diagnostics => (; cooks_threshold = 1.0, dfbeta_threshold = 0.2) => :lambdaz_diagnostics])

# View results
println(format_diagnostics(report))
NCA.LambdazDiagnostics — Type
Experimental

The LambdazDiagnostics struct and the lambdaz_diagnostics / format_diagnostics / exclude_lambdaz workflow are experimental. Field names, default thresholds, and output formatting may change without a deprecation cycle.

Per-point regression diagnostics for the λz terminal elimination fit.

Fields:

  • time: timepoints in the regression window
  • observed: observed concentrations
  • predicted: concentrations predicted by the log-linear model
  • residual: log-scale residuals (log(observed) − log(predicted))
  • studentized_residual: externally studentized residuals (t-distributed under H₀)
  • leverage: hat matrix diagonal values (influence of each point's x-position)
  • adjr2_influence: change in adjusted R² when each point is removed (leave-one-out)
  • outlier: true for points flagged by any active criterion
  • outlier_criteria: names of criteria that triggered for each point (e.g. ["SR", "CD"])
  • cooks_distance: Cook's distance measuring overall influence on both coefficients
  • dfbeta_lambdaz: change in slope (β₁) when each point is removed
  • loo_lambdaz: leave-one-out λz estimates
  • loo_thalf: leave-one-out t½ estimates
  • thresholds: OutlierThresholds recording the cutoffs used
  • press: PRESS statistic (predicted residual error sum of squares)
NCA.OutlierThresholds — Type

Thresholds used for outlier detection in lambdaz_diagnostics.

Fields:

  • alpha: significance level for Bonferroni-corrected studentized residual test
  • studentized_threshold: critical value derived from alpha (computed internally)
  • cooks_threshold: Cook's distance cutoff, or nothing if not active
  • leverage_threshold: hat matrix diagonal cutoff, or nothing if not active
  • dfbeta_threshold: max fractional change in λz cutoff, or nothing if not active

Formatting & Display

NCA.format_diagnostics — Function
format_diagnostics(diag::LambdazDiagnostics; fit=nothing, subject_id=nothing, profile=nothing, span=nothing, auc_extrap_pct=nothing)
Experimental

Output format may change without a deprecation cycle.

Format lambdaz_diagnostics output as a human/LLM-readable string.

Output structure:

  1. Header: subject/profile ID with λz, t½, n points, adjR², SE, CV%
  2. Thresholds: active outlier criteria and their cutoff values
  3. Quality metrics: PRESS, span (if provided), % AUC extrapolated (if provided)
  4. Point table: each regression timepoint with observed/predicted concentrations, studentized residual, leverage, Cook's distance, DFBETA, and outlier flag
  5. Footer: flagged outlier count and which criteria triggered

The span and auc_extrap_pct columns display only when provided.

Arguments

  • diag: LambdazDiagnostics from lambdaz_diagnostics, or missing
  • fit: optional lambdaz_fit result for summary header (includes SE and CV%)
  • subject_id: optional subject identifier for header
  • profile: optional profile number for header
  • span: optional span ratio (trange / t½) for quality context
  • auc_extrap_pct: optional % AUC extrapolated for quality context
format_diagnostics(df::DataFrames.AbstractDataFrame; only_outliers=true)
Experimental

Output format may change without a deprecation cycle.

Format diagnostics for all subjects in a run_nca result DataFrame.

Requires a lambdaz_diagnostics column. Auto-detects and uses lambdaz_fit, id, profile, span, and auc_extrap_percent_obs columns when present.

Set only_outliers=false to include all subjects, not just those with flagged outliers.

Outlier Exclusion

NCA.exclude_lambdaz — Function
exclude_lambdaz(pop, report; exclude=nothing) -> DataFrame
Experimental

Behaviour and signature may change without a deprecation cycle.

Build lambdaz_mask excluding outlier timepoints and return a copy of pop.

Intended workflow:

  1. Run diagnostics: report = run_nca(pop, [:lambdaz_fit, :lambdaz_diagnostics])
  2. Review results: println(format_diagnostics(report))
  3. Exclude outliers: pop2 = exclude_lambdaz(pop, report)
  4. Re-run NCA: report2 = run_nca(pop2, [...])

Only affects the λz regression window — other NCA parameters (Cmax, Tmax, etc.) are computed from the full concentration-time profile regardless of the mask.

Modes

  • Auto (exclude=nothing): excludes all points flagged in lambdaz_diagnostics. Requires both :lambdaz_fit and :lambdaz_diagnostics in report.
  • Manual (exclude=Dict(profile => [timepoints...])): excludes specific timepoints by profile number. Only requires :lambdaz_fit in report.

Use auto mode after reviewing format_diagnostics output. Use manual mode when you want precise control over which timepoints to exclude.

Arguments

  • pop: DataFrame from read_nca / read_nca_pumas
  • report: DataFrame from run_nca (must include :lambdaz_fit; auto mode also requires :lambdaz_diagnostics)
  • exclude: Dict(profile => [timepoints...]) or nothing (default)

Unmodified profiles keep missing mask values (automatic λz determination). Modified profiles get Bool for every row within the profile.

Example

pop = read_nca_pumas(df)
report = run_nca(pop, [:lambdaz_fit,
  :lambdaz_diagnostics => (; cooks_threshold = 1.0, dfbeta_threshold = 0.2) => :lambdaz_diagnostics])

# Review diagnostics
println(format_diagnostics(report))

# Auto-exclude all flagged outliers
pop2 = exclude_lambdaz(pop, report)

# Or exclude specific timepoints by profile number
pop2 = exclude_lambdaz(pop, report; exclude = Dict(1 => [71.9], 3 => [60.0]))

# Re-run NCA with cleaned data
report2 = run_nca(pop2, [:lambdaz_fit, :lambdaz_diagnostics])