Bioequivalence

Example Codes:

Bioequivalence vs Non-inferiority vs Inferiority

When conducting a clinical trial, a hypothesis of interest needs to be identified and defined. Various statistical techniques can be used to address the chosen hypothesis, depending on the type of comparison that is being made. The most common comparison is between the effects of a new treatment compared to the current treatment. That said, the specific comparison of interest will shape the hypothesis and in turn, the statistical method required.

There are three possible hypothesis that can be formulated when comparing two treatments:

1.              The new treatment is at least as effective as the current treatment (non-inferiority)

2.              The new treatment is strictly more effective than the current treatment (inferiority)

3.              The new treatment is equivalent to the current treatment (bioequivalence)

While these three possible hypothesis appear to be similar, they are slightly different, and thus require slightly different statistical tests.

Non-inferiority trails are used to test whether a minimum level of efficacy has been achieved in the new treatment.  These trials are designed to show that the new treatment is no less effective than the existing treatment.

Inferiority/superiority trials are used to test whether the new treatment is strictly more effective than the current treatment. These trials are designed to detect a difference between treatments.

Bioequivalence trials are used to test whether a new treatment is the same, within an acceptable range, to the current treatment. These trials are designed to confirm the absence of a meaningful difference between treatments.

Before we define the hypothesis’ and their corresponding statistical test, it important to identify the type of outcome variable that is of interest.

Outcome Variable Type

2.1 Binary Outcome

Unpaired

Non-inferiority:

vs

Inferiority:

vs

Bioequivalence:

vs

and

Code Example in SAS (non-inferiority)

/* Binary outcome */

/* Unpaired */

data table_unpair;

/* Data */

p1=0.4203;

p2=0.4638;

n1=69;n2=69;

/* Calculation */

theta=p1-p2;

var=(p1*(1-p1)/n1)+(p2*(1-p2)/n2);

se=sqrt(var);

delta=0.1; /* Pick a value of delta */

zright=(theta+delta)/se; /* z-score for Non-inferiority */

zleft=(theta-delta)/se; /* z-score for Inferiority */

pright=1-cdf("normal",zright); /* p-value for Non-inferiority */

pleft=cdf("normal",zleft); /* p-value for Inferiority */

pboth=pright+pleft; /* p-value for Bioequivalence */

run;

/* Paired */

data table;

/* Data */

p1=0.4203; *p1=proportion of 1 in protocol 1;

p2=0.4638; *p2=proportion of 1 in protocol 2;

p10=0;

p01=0.0435;

n=69;

/* Calculation */

theta=p1-p2;

var=(p10+p01-theta*theta)/n;

se=sqrt(var);

delta=0.1; /* Pick a value of delta */

zright=(theta+delta)/se; *two-tailed test; /* z-score for Non-inferiority */

zleft=(theta-delta)/se; *two-tailed test; /* z-score for Inferiority */

pright=1-cdf("normal",zright); /* p-value for Non-inferiority */

pleft=cdf("normal",zleft); /* p-value for Inferiority */

pboth=pright+pleft; /* p-value for Bioequivalence */

run;

/* Continuous outcome */

/* Unpaired */

data Process;

input _STAT_ \$4. @6 Process \$3. @10 Quality Yield Waste;

cards;

N New 27 27 27

MEAN New 34.6667 50.0000 11.9889

STD New 1.8605 0.8321 2.2548

N Old 27 27 27

MEAN Old 19.9530 40.1481 10.3556

STD Old 0.8077 0.7698 2.1445

;

/* Non-inferiority */

proc ttest data=Process sides=U h0=-0.1 /*delta*/ ;

class Process;

var Waste;

run;

/* Inferiority */

proc ttest data=Process sides=L h0=0.1 /*delta*/ ;

class Process;

var Waste;

run;

/* Bioequivalence: p-value of Non-inferiority + p-value of Inferiority */

/* Paired */

DATA WEIGHT;

INPUT WBEFORE WAFTER;

DATALINES;

200 185

175 154

188 176

198 193

197 198

310 275

245 224

202 188

;

RUN;

/* Non-inferiority */

proc ttest data=WEIGHT sides=U h0=-0.1 /*delta*/ ;

Paired WBEFORE * WAFTER;

run;

/* Inferiority */

proc ttest data=WEIGHT sides=L h0=0.1 /*delta*/ ;

Paired WBEFORE * WAFTER;

run;

/* Bioequivalence: p-value of Non-inferiority + p-value of Inferiority */

Code Example in R (non-inferiority)

install.packages("tidyverse")

library(tidyverse)

# Binary

# Unpaired

p1=0.4203

p2=0.4638

theta=p1-p2

n1=69;n2=69

var=(p1*(1-p1)/n1)+(p2*(1-p2)/n2)

se=sqrt(var)

delta=0.1

zright=(theta+delta)/se

zleft=(theta-delta)/se

pright=1-pnorm(zright)

pleft=pnorm(zleft)

print(paste("Non-inferiority: ", "z-score:", zright, "p-value:", pright))

print(paste("Inferiority: ", "z-score:", zleft, "p-value:", pleft))

print(paste("Bioequivalence: ", "p-value:", pright+pleft))

# Paired

p1=0.4203

p2=0.4638

p10=0

p01=0.0435

theta=p1-p2

n=69

var=(p10+p01-theta*theta)/n

se=sqrt(var)

delta=0.1

zright=(theta+delta)/se

zleft=(theta-delta)/se

pright=1-pnorm(zright)

pleft=pnorm(zleft)

print(paste("Non-inferiority: ", "z-score:", zright, "p-value:", pright))

print(paste("Inferiority: ", "z-score:", zleft, "p-value:", pleft))

print(paste("Bioequivalence: ", "p-value:", pright+pleft))

# Continuous

# Unpaired

# Data

process = data.frame(

process = c(rep("NEW", 27), rep("OLD", 27)),

quality = c(rnorm(27, 34.6667, 1.8605), rnorm(27, 19.9530, 0.8077)),

yield = c(rnorm(27, 50, 0.8321), rnorm(27, 40.1481, 0.7698)),

waste = c(rnorm(27, 11.9889, 2.2548), rnorm(27, 10.3556, 2.1445))

)

process_new = filter(process, process == "NEW")

process_old = filter(process, process == "OLD")

## Set a delta value

delta = 0.1

## Non-inferiority

t.test(process_new\$waste, process_old\$waste, mu = -delta, alternative = "greater")

## Inferiority

t.test(process_new\$waste, process_old\$waste, mu = delta, alternative = "less")

## Bioequivalence

p1 = t.test(process_new\$waste, process_old\$waste, mu = delta, alternative = "less")\$p.value

p2 = t.test(process_new\$waste, process_old\$waste, mu = -delta, alternative = "greater")\$p.value

print(paste("Bioequivalence p-value: ", p1+p2))

# Paired

# Data

weight = data.frame(

wbefore = c(200,175,188,198,197,310,245,202),

wafter = c(185,154,176,193,198,275,224,188)

)

## Non-inferiority

t.test(weight\$wbefore, weight\$wafter, paired = T, mu = -delta, alternative = "greater")

## Inferiority

t.test(weight\$wbefore, weight\$wafter, paired = T, mu = delta, alternative = "less")

## Bioequivalence

p1 = t.test(weight\$wbefore, weight\$wafter, paired = T, mu = delta, alternative = "less")\$p.value

p2 = t.test(weight\$wbefore, weight\$wafter, paired = T, mu = -delta, alternative = "greater")\$p.value

print(paste("Bioequivalence p-value: ", p1+p2))

References

2.     Althunian, T. A., de Boer, A., Groenwold, R. H. H., & Klungel, O. H. (2017). Defining the            noninferiority margin and analysing noninferiority: An overview. British Journal of Clinical           Pharmacology

3.     Committee for Proprietary Medicinal Products. (2001). Points to consider on switching between superiority and non-inferiority. British Journal of Clinical Pharmacology

4.     Tsong, Y., Zhang, J., & Levenson, M. (2007). Choice of δ noninferiority margin and dependency of the noninferiority trials. Journal of Biopharmaceutical Statistics

5.     Wang, B., Wang, H., Tu, X. M., & Feng, C. (2017). Comparisons of Superiority, Non-inferiority, and Equivalence Trials. Shanghai Archives of Psychiatry