expirest_wisle {expirest} | R Documentation |
What-if (approach for) shelf life estimation (wisle)
Description
Based on a linear regression model fitted to a stability data set the
function expirest_wisle()
estimates the shelf life, or retest period,
for the specified release and specification limit following the ARGPM
guidance “Stability testing for prescription medicines”. The
abbreviation “wisle” stands for “what-if shelf life estimation”
(because it estimates the shelf life (“what”) for a given release
limit (“if”)).
Usage
expirest_wisle(
data,
response_vbl,
time_vbl,
batch_vbl,
rl,
rl_sf,
sl,
sl_sf,
srch_range,
alpha = 0.05,
alpha_pool = 0.25,
xform = c("no", "no"),
shift = c(0, 0),
sf_option = "tight",
ivl = "confidence",
ivl_type = "one.sided",
ivl_side = "lower",
...
)
Arguments
data |
A data frame with the columns specified by |
response_vbl |
A character string that specifies the response variable
name that must be a column of |
time_vbl |
A character string that specifies the time variable name
that must be a column of |
batch_vbl |
A character string that specifies the column in |
rl |
A numeric value or a numeric vector that specifies the release specification limit(s) for which the corresponding expiry should be estimated. |
rl_sf |
A positive integer or a vector of positive integers that
specifies the number of “significant figures” (sf) of |
sl |
A numeric value or a numeric vector of length |
sl_sf |
A positive integer or a vector of positive integers that
specifies the number of “significant figures” (sf) of |
srch_range |
A vector of length |
alpha |
A numeric value between 0 and 1 that specifies the significance
level for the calculation of confidence or prediction intervals. The
default is |
alpha_pool |
A numeric value between 0 and 1 that specifies the type I
error rate for the test of the poolability of the batches. The default
is |
xform |
A vector of two character strings that specifies the
transformation of the response and the time variable. The default is
“no” transformation, i.e. |
shift |
A vector of two values which will be added to the variables
|
sf_option |
A character string that specifies if the limits ( |
ivl |
A character string of either |
ivl_type |
A character string that specifies if a “one sided”
or a “two sided” interval should be calculated, i.e. either
|
ivl_side |
A character string that specifies if the “upper” or
the “lower” limit is the relevant limit, i.e. either |
... |
Additional named or unnamed arguments passed on to
|
Details
For the shelf life estimation for submissions in Australia the Australian Regulatory Guidelines for Prescription Medicines (ARGPM), i.e. the guidance “Stability testing for prescription medicines”, is binding. In chapter 14.3.1, “Predicting shelf life from stability data”, it is described how the estimation should be done. It recommends to take the worst case situation at batch release into account. The following examples are listed:
- 1a)
For medicine that has a lower Assay release limit of 95 per cent and a lower assay expiry limit of 90 per cent, the maximum decrease in assay allowed over the shelf-life is 5 per cent.
- 2a)
Similarly, for a medicine that has a release limit for an individual impurity of 0.2 per cent and an expiry limit of 0.5 per cent, the maximum increase in the impurity allowed over the shelf life is 0.3 per cent.
- 1b)
For the same medicine, if the actual release assay result is 101 per cent, then the shelf life should be determined at the time the medicine (or confidence interval of the regression line) decreases by 5 per cent and reaches 96 per cent, rather than the expiry limit (90 per cent). This takes into account the possibility of batches being released at the lower release limit (i.e. 95 per cent) and ensures they will comply with the expiry limit throughout the shelf life.
- 2b)
Similarly, if the actual impurity content is 0.1 per cent at batch release, the shelf life should be determined as the time the 95 per cent confidence interval reaches 0.4 per cent (i.e. increases by 0.3 per cent).
Consequently, it is necessary to define
a release limit and
an expiry limit or shelf life limit (usually the specification limit).
If both of these limits were the same the shelf life would be zero, i.e. no
change allowed.
For the estimation of the shelf life or expiry limit it is necessary to find
the point where the upper or lower 95% confidence interval limit of the
linear model fitted to the data (by aid of lm
) intersects the
“worst case scenario limit” (WCSL), which is defined by the ARGPM
guidance “Stability testing for prescription medicines” as the
intercept \pm
difference between the specification limit and the
release limit, where this differences is added (+
) if the upper limit
is relevant or it is subtracted (-
) if the lower limit is relevant.
In this package, this point is called the “point of intersection” or
“point of interest”, abbreviated POI.
Before performing the retest period or shelf life estimation the most suitable model should be determined. It should particularly be verified if data of all test batches are poolable or not. Details on this are described in section “Checking batch poolability” below.
Value
An object of class ‘expirest_wisle
’ is returned,
containing the following elements:
Data |
Data frame of the original data including new columns with transformed variables, if applicable. |
Parameters |
A list of the parameters with the elements |
Variables |
A list of the variable names, i.e. the original names of
|
Model.Type |
A list of two elements that specifies which model, based
on the ANCOVA analysis, suits best. The first element ( |
Models |
A list of four elements named |
AIC |
A numeric named vector of the Akaike Information Criterion (AIC)
values of the |
BIC |
A numeric named vector of the Bayesian Information Criterion (BIC)
values of each of the |
wc.icpt |
A data frame of the worst case intercepts of each of the four fitted models. |
wc.batch |
A list of numeric value(s) of the worst case batch(es) per model type. |
Limits |
A list of all limits. |
POI |
A data frame of the intercepts, the differences between release and shelf life limits, the WCSLs, the expiry and release specification limits, the shelf lives and POI values. |
Structure of the POI
data frame:
Intercept.cics |
The intercept of the worst case batch of the cics model. |
Intercept.dics |
The intercept of the worst case batch of the dics model. |
Intercept.dids.pmse |
The intercept of the worst case batch of the dids model with pooled mean square error (pmse). |
Intercept.dids |
The intercept of the worst case batch of the dids model obtained by fitting individual models to the data of each batch. |
Delta.cics |
Absolute difference between the release and and the shelf life specification of the cics model. |
Delta.dics |
Absolute difference between the release and and the shelf life specification of the dics model. |
Delta.dids.pmse |
Absolute difference between the release and and the shelf life specification of the dids model with pooled mean square error (pmse). |
Delta.dids |
Absolute difference between the release and and the shelf life specification of the dids model obtained by fitting individual models to the data of each batch. |
WCSL.cics |
WCSL of the cics model. |
WCSL.dics |
WCSL of the dics model. |
WCSL.dids.pmse |
WCSL of the dids model with pooled mean square error (pmse). |
WCSL.dids |
WCSL of the dids model obtained by fitting individual models to the data of each batch. |
Exp.Spec |
The (expiry) specification, i.e. the specification which is relevant for the determination of the expiry. |
Rel.Spec |
The calculated release specification. |
Shelf.Life.cics |
The estimated shelf life of the cics model. |
Shelf.Life.dics |
The estimated shelf life of the dics model. |
Shelf.Life.dids.pmse |
The estimated shelf life of the dids model with pooled mean square error (pmse). |
Shelf.Life.dids |
The estimated shelf life of the dids model obtained by fitting individual models to the data of each batch. |
POI.Model.cics |
The POI of the cics model. |
POI.Model.dics |
The POI of the dics model. |
POI.Model.dids.pmse |
The POI of the dids model with pooled mean square error (pmse). |
POI.Model.dids |
The POI of the dids model obtained by fitting individual models to the data of each batch. |
Checking batch poolability
According to ICH Q1E guideline, construction of the 95% confidence interval
on the basis of the combined data of all test batches is allowed only if it
has been confirmed by aid of a statistical test whether the regression lines
from the different batches have a common slope and a common intercept. A
significance level of alpha_pool = 0.25
should to be used for both
batch-related terms, and the test of the slopes has to precede the test of
the intercepts. From these tests, three possible models may be appropriate,
i.e.
a common intercept / common slope model (cics),
a different intercept / common slope model (dics) or
a different intercept / different slope model (dids).
The common intercept / different slope model is not of practical relevance because the corresponding model is missing an effect. If the slopes are significantly different, there is no point comparing intercepts. The dids model has individual intercepts and individual slopes, and the calculation of confidence intervals is based on the corresponding individual mean square errors. The different intercept / different slope model where the mean square error is pooled across batches is reported as dids.pmse.
These requirements can be checked by aid of an “ANalysis of
COVAriance” (ANCOVA) including the batch variable as main effect and as
batch \times time
interaction term. The full ANCOVA model
simultaneously tests all the effects, and non-significant effects can be
identified and removed for fitting of the final regression model that is
used for the estimation of the shelf life or retest period.
The significance level (alpha_pool = 0.25
, Type I error) is used to
increase the power of the test to detect cases where the data should not be
pooled. Setting alpha_pool = 0.25
decreases the probability of
incorrectly concluding that stability data from multiple batches can be
pooled. On the other hand, though, it increases the probability of using a
single batch to determine expiry when pooling batches would be more
appropriate.
References
Therapeutic Goods Administration (TGA) of the Department of Health of the Australian Government, Australian Regulatory Guidelines for Prescription Medicines (ARGPM), Stability testing for prescription medicines, Version 1.1, March 2017
International Council for Harmonisation of Technical Requirements for Registration of Pharmaceuticals for Human (ICH), Harmonised Tripartite Guideline, Evaluation of Stability Data Q1E, step 4, February 2003 (CPMP/ICH/420/02).
See Also
expirest_osle
, uniroot
,
lm
, AIC
, BIC
.
Examples
# Successful estimations
# A model with common intercepts / common slopes (cics)
res1 <-
expirest_wisle(data = exp1[exp1$Batch %in% c("b2", "b5", "b7"), ],
response_vbl = "Potency", time_vbl = "Month",
batch_vbl = "Batch", rl = 98, rl_sf = 3, sl = 95,
sl_sf = 3, srch_range = c(0, 500), sf_option = "loose")
res1$Model.Type
res1$POI
# Expected results in res1$Model.Type
# $type.spec
# common.icpt common.slp
# 1 1
#
# $type.acronym
# [1] "cics"
# (Expected) results in res1$POI
# Intercept.cics Intercept.dics Intercept.dids Intercept.dids.pmse Delta.cics
# 100.5669 100.3638 100.2491 100.2491 3
# Delta.dics Delta.dids Delta.dids.pmse WCSL.cics WCSL.dics WCSL.dids
# 3 3 3 97.56688 97.36375 97.24914
# WCSL.dids.pmse Exp.Spec.Report Exp.Spec Rel.Spec.Report Rel.Spec
# 97.24914 95 94.95 98 97.95
# Shelf.Life.cics Shelf.Life.dics Shelf.Life.dids Shelf.Life.dids.pmse
# 14.07398 13.23176 13.34561 13.80695
# POI.Model.cics POI.Model.dics POI.Model.dids POI.Model.dids.pmse
# 26.2241 24.8003 23.34184 23.66724
# The parameter settings sf_option = "loose" and ivl_side = "lower" (the
# default setting of ivl_side) cause the specification limit of 95.0
# (sl_sf = 3, i.e. 3 significant digits) to be reduced by 0.05, i.e. the
# actual specification limit is 94.95. Analogously, the release limit of 98.0
# is reduced to 97.95.
# A model with different intercepts / different slopes (dids)
res2 <-
expirest_wisle(data = exp1[exp1$Batch %in% c("b4", "b5", "b8"), ],
response_vbl = "Potency", time_vbl = "Month",
batch_vbl = "Batch", rl = 98, rl_sf = 3, sl = 95,
sl_sf = 3, srch_range = c(0, 500), sf_option = "loose")
res2$Model.Type
res2$POI
# Expected results in res2$Model.Type
# $type.spec
# common.icpt common.slp
# 0 0
#
# $type.acronym
# [1] "dids"
# (Expected) results in res2$POI
# Intercept.cics Intercept.dics Intercept.dids Intercept.dids.pmse Delta.cics
# 101.5498 100.4882 101.2594 101.2594 3
# Delta.dics Delta.dids Delta.dids.pmse WCSL.cics WCSL.dics WCSL.dids
# 3 3 3 98.54976 97.48822 98.25938
# WCSL.dids.pmse Exp.Spec.Report Exp.Spec Rel.Spec.Report Rel.Spec
# 98.25938 95 94.95 98 97.95
# Shelf.Life.cics Shelf.Life.dics Shelf.Life.dids Shelf.Life.dids.pmse
# 13.03332 11.42141 7.619661 7.483223
# POI.Model.cics POI.Model.dics POI.Model.dids POI.Model.dids.pmse
# 28.12518 22.47939 15.96453 15.72348
# Analysis with a single batch (i.e. the worst case batch of res2 above)
res3 <-
expirest_wisle(data = exp1[exp1$Batch == "b8", ],
response_vbl = "Potency", time_vbl = "Month",
batch_vbl = "Batch", rl = 98, rl_sf = 3, sl = 95,
sl_sf = 3, srch_range = c(0, 500), sf_option = "loose")
res3$Model.Type
res3$POI
# Since only one batch is involved there is no model type. Nevertheless, the
# result is reported under the dids model name.
# Expected results in res3$Model.Type
# $type.spec
# common.icpt common.slp
# NA NA
#
# $type.acronym
# [1] "n.a."
# (Expected) results in res3$POI
# Intercept.cics Intercept.dics Intercept.dids Intercept.dids.pmse Delta.cics
# NA NA 101.2594 NA NA
# Delta.dics Delta.dids Delta.dids.pmse WCSL.cics WCSL.dics WCSL.dids
# NA 3 NA NA NA 98.25938
# WCSL.dids.pmse Exp.Spec.Report Exp.Spec Rel.Spec.Report Rel.Spec
# NA 95 94.95 98 97.95
# Shelf.Life.cics Shelf.Life.dics Shelf.Life.dids Shelf.Life.dids.pmse
# NA NA 7.619661 NA
# POI.Model.cics POI.Model.dics POI.Model.dids POI.Model.dids.pmse
# NA NA 15.96453 NA
# Unsuccessful estimation
## Not run:
# The interval does not cross the limit (i.e. not within srch_range).
res4 <-
expirest_wisle(data = exp1[exp1$Batch %in% c("b2", "b5", "b7"), ],
response_vbl = "Potency", time_vbl = "Month",
batch_vbl = "Batch", rl = 98, rl_sf = 3, sl = 105,
sl_sf = 4, srch_range = c(0, 500), sf_option = "loose",
ivl_side = "upper")
res4$POI
# (Expected) results in res3$POI
# Intercept.cics Intercept.dics Intercept.dids Intercept.dids.pmse Delta.cics
# 100.5669 NA NA NA 3
# Delta.dics Delta.dids Delta.dids.pmse WCSL.cics WCSL.dics WCSL.dids
# NA NA NA 107.5669 NA NA
# WCSL.dids.pmse Exp.Spec.Report Exp.Spec Rel.Spec.Report Rel.Spec
# NA 105 105.04 98 98.04
# Shelf.Life.cics Shelf.Life.dics Shelf.Life.dids Shelf.Life.dids.pmse
# NA NA NA NA
# POI.Model.cics POI.Model.dics POI.Model.dids POI.Model.dids.pmse
# NA NA NA NA
# Estimation may also fail because of an inappropriate 'srch_range' setting.
res5 <-
expirest_wisle(data = exp1[exp1$Batch %in% c("b2", "b5", "b7"), ],
response_vbl = "Potency", time_vbl = "Month",
batch_vbl = "Batch", rl = 98, rl_sf = 3, sl = 95,
sl_sf = 3, srch_range = c(0, 5), sf_option = "loose")
res5$POI
# (Expected) results in res4$POI
# Intercept.cics Intercept.dics Intercept.dids Intercept.dids.pmse Delta.cics
# 100.5669 NA NA NA 3
# Delta.dics Delta.dids Delta.dids.pmse WCSL.cics WCSL.dics WCSL.dids
# NA NA NA 97.56688 NA NA
# WCSL.dids.pmse Exp.Spec.Report Exp.Spec Rel.Spec.Report Rel.Spec
# NA 95 94.95 98 97.95
# Shelf.Life.cics Shelf.Life.dics Shelf.Life.dids Shelf.Life.dids.pmse
# NA NA NA NA
# POI.Model.cics POI.Model.dics POI.Model.dids POI.Model.dids.pmse
# NA NA NA NA
## End(Not run)