feat: add bioequivalence inferential statistics functions#547
Open
billdenney wants to merge 15 commits into
Open
feat: add bioequivalence inferential statistics functions#547billdenney wants to merge 15 commits into
billdenney wants to merge 15 commits into
Conversation
…set, I get the warning; 'No grouping variables found in the PKNCA object. Defaulting to '~ sequence + occasion + formulation'and error message; 'Reference value, "3", not found in column, "form". No sure why but can confirm that those messages work.
Add fitbe_models(), fitbe_table(), and fitbe_calculate() to compute average bioequivalence statistics from NCA results: per-endpoint linear mixed-effects models on log-transformed values, geometric mean ratios with 90 percent confidence intervals, Satterthwaite degrees of freedom, and intra-subject CV. The functions consume the long-format output of a PKNCAresults object directly. The statistical engine packages (lme4, lmerTest, emmeans) are Suggests and guarded with requireNamespace(); tests skip when they are absent. Adds the v50-bioequivalence vignette, tests, and documentation. Formalizes the prototype workflow from PR 490. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Member
Author
|
Based on the functions @Sang-j111 build in #490 |
Starting-point design for extending the bioequivalence functions on this branch (PR #547) into the full reference-scaled / regulatory assessment space of replicateBE (EMA/HC/GCC ABEL) and PowerTOST (FDA RSABE/NTID), plus a regulatory-comparison assessor and the nlmixr2mbbe integration contract. Build-ignored under design/. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # NEWS.md
… layer Add a regulatory bioequivalence decision and reference-scaling layer on top of the average-BE (fitbe_*) foundation, covering all major frameworks: * be_assess() - full pass/fail assessment for ABE, EMA/HC/GCC expanding limits (ABEL), and the FDA reference-scaled RSABE/NTID/HVNTID frameworks. Accepts a PKNCAresults object or a tidy long data.frame. * be_compare() - assess one dataset under several frameworks side by side. * be_regulator() / be_expand_limits() - internalized regulatory constants and scaled acceptance limits (single source of truth). * be_design() - crossover design classification and framework feasibility. * be_within_var() - within-subject variability (swR/swT, CVwR/CVwT, swT:swR ratio CI) by ANOVA (default) or a mixed model. * print/format/summary/as.data.frame methods for the new classes. All regulatory constants and criteria are internalized, so PKNCA does not depend on PowerTOST or replicateBE; the implementation was validated against those packages during development and the tests pin the resulting expected values (within-subject variances match replicateBE's estimator and the ABEL limits match its scaled-limit output exactly). The FDA RSABE/NTID/HVNTID criteria implement the linearized Howe/Hyslop bound from the guidances. Extends the v50-bioequivalence vignette with a reference-scaling section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Unify all nine bioequivalence functions (fitbe_* and be_*) under the capitalized @family Bioequivalence tag so they group under a single "Bioequivalence" heading. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
billdenney
commented
Jun 10, 2026
| group_cols <- NULL | ||
| if (inherits(object, "PKNCAresults")) { | ||
| assert_PKNCAresults(object) | ||
| data <- as.data.frame(as.data.frame(object, filter_excluded = TRUE)) |
Member
Author
There was a problem hiding this comment.
Please only use as.data.frame() once.
Replace every function defined inside another bioequivalence function with a top-level helper or a base-R primitive, so no closures are created per call and the helpers are independently testable: * be_within_var(): arm_var_anova() -> .be_arm_var() / .be_arm_var_na() * be_design(): the per-subject pattern lambda -> .be_subject_pattern(); the replication-count lambdas vectorized (tapply over a logical); the first-value lambda -> `[`; drop the unused per_order line * .be_isc(): the per-subject contrast lambda -> .be_subject_ilat() * be_compare(): tryCatch() with an inline error handler -> try() + inherits() * summary.be_compare(): the cell-selection lambda -> `[` No behavior change; all bioequivalence tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge the original bioequivalence workflow prototype from Natalie Sang's PR #490 (#490) to preserve her development history and credit the inspirational work. The prototype (BA_BEworkflow/NCA_BEworkflow.Rmd, with fit_BE_endpoints(), create_BE_table(), calculate_BE()) inspired but is not directly used by the production implementation in R/bioequivalence.R; it is removed in the next commit. Co-authored-by: Natalie Sang <nataliesang143@gmail.com>
Delete BA_BEworkflow/NCA_BEworkflow.Rmd and pknca.Rproj, merged in the previous commit to preserve Natalie Sang's authorship. The prototype functions inspired the production fitbe_*/be_* implementation in R/bioequivalence.R but are not part of the package. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mechanical regeneration of all man/*.Rd and DESCRIPTION via roxygen2 8.0.0 (link syntax, whitespace, Config/roxygen2/version). No source changes. This commit is intentionally separate so the bioequivalence refactor that follows has a clean, reviewable documentation diff; reviewers can skip this formatting-only commit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collapse the two bioequivalence code paths (fitbe_models/fitbe_table/
fitbe_calculate and the be_assess internals) into one pipeline coordinated by
be_fit_models(), which runs, per endpoint:
be_dataset() -> be_fit_model_single() -> be_extract_param() -> be_table()
* be_dataset(): validate, resolve the value column, drop excluded rows, detect
the subject/sequence/period columns, and set the reference factor level.
* be_fit_model_single(): the only place models are fit; dispatches to
be_fit_model_lmer/nlme/anova.
* be_extract_param(): geometric means, GMR + CI, intra-subject contrasts, and
within-formulation variances; dispatches to be_extract_param_lmer/nlme/anova.
* be_table(): applies the regulator limits/criterion via the unchanged .be_*
deciders and decides pass/fail.
be_assess()/be_compare() are now thin verbs over be_fit_models(). The method =
"A"/"B" argument is replaced by an auto-selected model_type ("lmer"/"anova"/
"nlme"); be_within_var() likewise takes model_type. The fitbe_* functions are
removed (they were unreleased). Output is byte-identical to the previous
implementation (verified across all fixtures and regulators); nlme is a new
model_type option.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Credit Natalie Sang (@Sang-j111) for the bioequivalence prototype in PR #490 that inspired the bioequivalence functions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* be_design() now recommends a model type (2x2 crossover -> fixed-effects ANOVA, replicate -> mixed model), and .be_resolve_model_type() combines the regulator and design: the FDA family always uses intra-subject contrasts, otherwise the design decides. model_type = "nlme" requires a full replicate. * The table now reports, on the measurement scale, the reference and test geometric means with their 90% confidence intervals (gm_reference/gm_test and _lower/_upper bounds). * Units are extracted from the PKNCAresults object (PPSTRESU/PPORRESU), attached to the be_fit object as a `units` attribute (NULL when not provided), and emitted as a per-endpoint `units` column (they differ for Cmax vs AUC). Existing decision columns are byte-identical to before across all fixtures and regulators; the new columns are additive. Also regenerates man/PKNCA.Rd to list Natalie Sang as a contributor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add fitbe_models(), fitbe_table(), and fitbe_calculate() to compute average bioequivalence statistics from NCA results: per-endpoint linear mixed-effects models on log-transformed values, geometric mean ratios with 90 percent confidence intervals, Satterthwaite degrees of freedom, and intra-subject CV. The functions consume the long-format output of a PKNCAresults object directly.
The statistical engine packages (lme4, lmerTest, emmeans) are Suggests and guarded with requireNamespace(); tests skip when they are absent. Adds the v50-bioequivalence vignette, tests, and documentation. Formalizes the prototype workflow from PR 490.