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
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_maskmanually 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_thresholdand/ordfbeta_thresholdfor 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_diagnosticsto display results andexclude_lambdazto act on flagged outliers.
Keyword arguments
alpha=0.05: significance level for Bonferroni-corrected studentized residual testcooks_threshold=nothing: Cook's distance cutoff (e.g.1.0or4/n);nothing= inactiveleverage_threshold=nothing: hat matrix diagonal cutoff (e.g.4/n);nothing= inactivedfbeta_threshold=nothing: max fractional change in λz (e.g.0.2for 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
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 windowobserved: observed concentrationspredicted: concentrations predicted by the log-linear modelresidual: 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:truefor points flagged by any active criterionoutlier_criteria: names of criteria that triggered for each point (e.g.["SR", "CD"])cooks_distance: Cook's distance measuring overall influence on both coefficientsdfbeta_lambdaz: change in slope (β₁) when each point is removedloo_lambdaz: leave-one-out λz estimatesloo_thalf: leave-one-out t½ estimatesthresholds:OutlierThresholdsrecording the cutoffs usedpress: 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 teststudentized_threshold: critical value derived fromalpha(computed internally)cooks_threshold: Cook's distance cutoff, ornothingif not activeleverage_threshold: hat matrix diagonal cutoff, ornothingif not activedfbeta_threshold: max fractional change in λz cutoff, ornothingif 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)Format lambdaz_diagnostics output as a human/LLM-readable string.
Output structure:
- Header: subject/profile ID with λz, t½, n points, adjR², SE, CV%
- Thresholds: active outlier criteria and their cutoff values
- Quality metrics: PRESS, span (if provided), % AUC extrapolated (if provided)
- Point table: each regression timepoint with observed/predicted concentrations, studentized residual, leverage, Cook's distance, DFBETA, and outlier flag
- Footer: flagged outlier count and which criteria triggered
The span and auc_extrap_pct columns display only when provided.
Arguments
diag:LambdazDiagnosticsfromlambdaz_diagnostics, ormissingfit: optionallambdaz_fitresult for summary header (includes SE and CV%)subject_id: optional subject identifier for headerprofile: optional profile number for headerspan: optional span ratio (trange / t½) for quality contextauc_extrap_pct: optional % AUC extrapolated for quality context
format_diagnostics(df::DataFrames.AbstractDataFrame; only_outliers=true)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) -> DataFrameBuild lambdaz_mask excluding outlier timepoints and return a copy of pop.
Intended workflow:
- Run diagnostics:
report = run_nca(pop, [:lambdaz_fit, :lambdaz_diagnostics]) - Review results:
println(format_diagnostics(report)) - Exclude outliers:
pop2 = exclude_lambdaz(pop, report) - 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 inlambdaz_diagnostics. Requires both:lambdaz_fitand:lambdaz_diagnosticsinreport. - Manual (
exclude=Dict(profile => [timepoints...])): excludes specific timepoints by profile number. Only requires:lambdaz_fitinreport.
Use auto mode after reviewing format_diagnostics output. Use manual mode when you want precise control over which timepoints to exclude.
Arguments
pop: DataFrame fromread_nca/read_nca_pumasreport: DataFrame fromrun_nca(must include:lambdaz_fit; auto mode also requires:lambdaz_diagnostics)exclude:Dict(profile => [timepoints...])ornothing(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])