Trial biostatistics toolkit

Stage 5: QC and validation

Executed QC ledger: re-derivation by a second method

Executed here: same-author re-derivation

Synthetic data only: simulated for this worked example; not real trial data and not a regulatory deliverable.

Same-author re-derivation, not independent double programming. One person wrote the primary programs and these checks from the same SAP. The checks re-derive each result by a different method and compare with diffdf at the tolerances shown. They can catch coding slips and engine defaults; they cannot catch a misreading of the SAP that both routes share.

Executed QC ledger. Tolerances are absolute, in the units of each variable; 'exact' means identical values.
IDItemVariablePrimary routeQC routeComparedToleranceMismatchesMax abs diffStatus
Q1NCA parameters per profileCMAXPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileTMAXPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileTLSTPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileCLSTPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileAUCLSTPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-060≤ 1e-10pass
Q1NCA parameters per profileAUCIFOPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-060≤ 1e-10pass
Q1NCA parameters per profileAUCPEOPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-060≤ 1e-10pass
Q1NCA parameters per profileLAMZHLPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-060≤ 1e-10pass
Q1NCA parameters per profileLAMZPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileLAMZNPTPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 79exact00pass
Q1NCA parameters per profileR2ADJPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileLAMZLLPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1NCA parameters per profileLAMZULPKNCA 0.12.1 pk.nca()NonCompart 0.8.4 tblNCA(), plus the zero-segment trapezoid in base R 791e-090≤ 1e-10pass
Q1bNCA parameter rules: values flagged per profileAUCIFO_EXCLPKNCA exclude() (01_nca.R)base-R rule on the NonCompart values 79exact0pass
Q1bNCA parameter rules: values flagged per profileLAMZ_EXCLPKNCA exclude() (01_nca.R)base-R rule on the NonCompart values 79exact0pass
Q2BE ratio, 90% CI and within-participant CVratiolm() GLM (02_be.R)two-sample t-test on half period differences (closed form) 31e-100≤ 1e-10pass
Q2BE ratio, 90% CI and within-participant CVlowerlm() GLM (02_be.R)two-sample t-test on half period differences (closed form) 31e-100≤ 1e-10pass
Q2BE ratio, 90% CI and within-participant CVupperlm() GLM (02_be.R)two-sample t-test on half period differences (closed form) 31e-100≤ 1e-10pass
Q2BE ratio, 90% CI and within-participant CVcv_withinlm() GLM (02_be.R)two-sample t-test on half period differences (closed form) 31e-100≤ 1e-10pass
Q2BE ratio, 90% CI and within-participant CVdflm() GLM (02_be.R)two-sample t-test on half period differences (closed form) 3exact00pass
Q3BE ratio, 90% CI and within-participant CVratiolm() GLM (02_be.R)nlme::lme() REML, random participant 31e-060≤ 1e-10pass
Q3BE ratio, 90% CI and within-participant CVlowerlm() GLM (02_be.R)nlme::lme() REML, random participant 31e-0606.1e-10pass
Q3BE ratio, 90% CI and within-participant CVupperlm() GLM (02_be.R)nlme::lme() REML, random participant 31e-0606.9e-10pass
Q3BE ratio, 90% CI and within-participant CVcv_withinlm() GLM (02_be.R)nlme::lme() REML, random participant 31e-0601.6e-07pass
Q3BE ratio, 90% CI and within-participant CVdflm() GLM (02_be.R)nlme::lme() REML, random participant 3exact00pass
Q4ADPC relative timesNFRLTadmiral 1.5.0 ad_adpc.R patternbase-R difftime() on PCDTC and EXSTDTC1185exact00pass
Q4ADPC relative timesARRLTadmiral 1.5.0 ad_adpc.R patternbase-R difftime() on PCDTC and EXSTDTC11851e-0603.3e-09pass
Q4ADPC relative timesAFRLTadmiral 1.5.0 ad_adpc.R patternbase-R difftime() on PCDTC and EXSTDTC11851e-0603.3e-08pass
Q5ADSL population flagsSAFFLadmiral ADSL plus 05_adpp.R rulesbase R on DM, EX, PC, AE and PP 40exact0pass
Q5ADSL population flagsPKCFLadmiral ADSL plus 05_adpp.R rulesbase R on DM, EX, PC, AE and PP 40exact0pass
Q5ADSL population flagsPKPFLadmiral ADSL plus 05_adpp.R rulesbase R on DM, EX, PC, AE and PP 40exact0pass
Q5ADSL population flagsBEFLadmiral ADSL plus 05_adpp.R rulesbase R on DM, EX, PC, AE and PP 40exact0pass
Q6Table 14.3.1.1 displayed countsNrtables/tern table cellsbase-R count on AE and EX 2exact00pass
Q6Table 14.3.1.1 displayed countsanyrtables/tern table cellsbase-R count on AE and EX 2exact00pass
Q6Table 14.3.1.1 displayed countseventsrtables/tern table cellsbase-R count on AE and EX 2exact00pass
Q6Table 14.3.1.1 displayed countsrelatedrtables/tern table cellsbase-R count on AE and EX 2exact00pass
Q6Table 14.3.1.1 displayed countsseverertables/tern table cellsbase-R count on AE and EX 2exact00pass
Q6Table 14.3.1.1 displayed countsseriousrtables/tern table cellsbase-R count on AE and EX 2exact00pass
Q7Control: planted 0.1% change in one AUC(0-t); pass = exactly 1 mismatch foundAUCLSTPKNCA resultsthe same results with one value changed 791e-0611.4e+00pass
Q8Control: NonCompart AUC(0-t) without the zero-segment trapezoid; pass = mismatches in exactly the 1 profile(s) with a BLQ value between quantifiable samplesAUCLSTPKNCA resultsNonCompart tblNCA() as it comes 791e-0616.9e+01pass

How to read it

Files: qc_ledger.csv, qc_ledger.json, qc_nca_side_by_side.csv (PKNCA and NonCompart values for every profile). Program: study/05_qc/qc.R.

What the QC found while this example was built

The first full run had 6 failures out of the 37 checks it had then, all resolved; the fixes are in the code, not in the tolerances:

A later review added a BLQ value between quantifiable samples (scenario 6) so that the ICH M13A BLQ setting is exercised. Q1 then failed for that profile's AUC(0-t), AUC(0-inf) and extrapolated percentage: NonCompart gives a segment that falls to zero no area, while the SAP and PKNCA use the linear trapezoid. The QC route now adds that trapezoid, and Q8 checks that the difference is confined to that profile. The same review found that the SAP's adjusted R-squared and extrapolation thresholds were passed to PKNCA as options, which do nothing on their own; they are now applied with exclude() and checked in Q1b.

Not covered