Tutorial: Bioequivalence Convenience Layer¶
This tutorial demonstrates OpenPKFlow's lightweight paired TOST convenience layer. For formal regulator-facing BE analysis with ANOVA tables, replicate designs, NTI, ABEL/RSABE, and validation fixtures, export to BioEqPy.
1. Prepare the DataFrame¶
Create a wide-format DataFrame with one row per subject:
import pandas as pd
from openpkflow.be import BEStudy
df = pd.DataFrame({
"subject": ["S01", "S02", "S03", "S04", "S05", "S06"],
"sequence": ["RT", "RT", "RT", "TR", "TR", "TR"],
"reference": [100.2, 98.7, 105.1, 97.3, 102.8, 99.5],
"test": [95.1, 94.0, 99.8, 92.9, 97.4, 94.8],
})
study = BEStudy(df, parameter="AUCinf")
result = study.analyze()
print(result.summary())
Required columns: subject, reference, test.
The sequence column ("RT" / "TR") is optional for paired TOST, but required when exporting to BioEqPy.
2. Generate a report¶
3. Interpret results¶
| Output | Meaning |
|---|---|
| GMR | Geometric Mean Ratio (test / reference) |
| 90% CI | Confidence interval from TOST |
| Bioequivalent | True if 90% CI falls entirely within acceptance limits |
| Intra-subject CV% | Within-subject variability estimate |
The report includes a CI bar visualization placing the 90% CI against the acceptance window.
4. NTI products (narrow acceptance limits)¶
For narrow therapeutic index drugs, pass tighter limits:
5. From NCA results (convenience constructor)¶
If you ran NCA separately on each formulation, feed both
NCASummaryResults objects directly:
from openpkflow.be import BEStudy
from openpkflow.nca import NCAStudy
ref_nca = NCAStudy.from_csv("ref_pk.csv", auc_method="linear_up_log_down", blq_method="none")
tst_nca = NCAStudy.from_csv("tst_pk.csv", auc_method="linear_up_log_down", blq_method="none")
ref_summary = ref_nca.analyze()
tst_summary = tst_nca.analyze()
study = BEStudy.from_nca_results(ref_summary, tst_summary, parameter="AUCinf")
result = study.analyze()
print(result.summary())
Subjects are matched by ID. Only subjects present in both result sets are used.
6. Export to BioEqPy for formal BE¶
from bioeqpy import analyze
bioeqpy_table = study.to_bioeqpy_dataframe()
formal_results = analyze(
bioeqpy_table,
parameters=["AUCinf"],
report="bioeqpy_formal_be_report.html",
)
to_bioeqpy_dataframe() returns the long-format columns BioEqPy expects:
subject, sequence, period, treatment, and the selected PK parameter.
The export requires TR/RT sequence labels.
7. CLI¶
openpkflow be compare be_data.csv --parameter AUCinf
openpkflow be compare be_data.csv --parameter AUCinf --report be_report.html
CSV format: subject, sequence, reference, test
Statistical note¶
The TOST procedure tests two one-sided hypotheses:
- H01: GMR <= lower limit (e.g., 0.80)
- H02: GMR >= upper limit (e.g., 1.25)
Both are rejected at alpha=0.05 if and only if the 90% CI lies entirely within the acceptance window. This is mathematically equivalent to verifying that both one-sided t-tests pass at alpha=0.05.
Reference: Schuirmann (1987), J Pharmacokinet Biopharm 15(6):657-680. FDA guidance: Statistical Approaches to Establishing Bioequivalence (2001).