The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
This package implements the stage life testing (SLT)
model of Laumen & Cramer (2019, Naval Research Logistics
66:632-647), which unifies progressive censoring (with fixed censoring
times) and step-stress accelerated life testing. Units begin on a
baseline stage and, at a fixed stage-change time tau1,
R*_1 of the units still surviving are randomly selected and
moved to an elevated stage; the rest continue failing under the original
stage conditions. [rslt()] is this package’s only
data-generating function, implementing the paper’s own Procedure 2.3.
R*_1 is generated by one of two rules:
design = "typeP" transfers a fixed target
proportion pi1 of survivors:
R*_1 = floor(pi1 * (n - D1)), where D1 is the
number of stage-0 failures observed before tau1.design = "typeM" transfers a fixed target
count R0_1, capped by the number of survivors
actually available.Setting pi1 = 1 (every survivor transferred) collapses
the model to the classical “simple step-stress” design – Remark 2.2(4)
of the paper – which is why no separate function is needed for that
case: it is simply
rslt(..., design = "typeP", prop_transfer = 1). This is
also the structure of a typical published step-stress data set
(see Section 8), so it is the default prop_transfer used
throughout this vignette’s non-Section-5 examples for simplicity, even
though the package’s actual namesake model is the general
random-withdrawal case.
The two stages are linked by the cumulative exposure
model: a unit that has survived to time tau under
the baseline stage is treated, after switching, as if it had already
accumulated an equivalent age
\[ \nu = Q\big(F(\tau;\theta_0);\ \theta_1\big) \]
under the elevated-stage distribution, where
F/Q are the CDF/quantile function of a common
two-parameter baseline family \theta = (\lambda, \alpha)
(lambda a rate/scale-type parameter, alpha a
shape parameter). [slt_equiv_age()] computes
\nu directly, and this exactly reproduces equation (1.1) of
the paper. [dslt()], [pslt()] and
[qslt()] give the density/CDF/quantile function of a single
unit’s marginal lifetime under this model – but note that these are only
the correct pooled reference distribution for the combined
Y/Z sample when
prop_transfer = 1; see the note in
[slt_gof_ks()] for why.
A parameterisation note for anyone comparing directly against
the paper’s tables: the paper parameterises the
Exponential/Weibull distributions by their mean
\theta (F(x) = 1 - exp(-x/\theta)), whereas
this package parameterises every family by a rate-like
lambda (F(x) = 1 - exp(-\lambda x) for the
alpha=1 case), so lambda = 1/\theta. Section 5.1 below
reproduces the paper’s own worked example numerically, using this
correspondence.
slt_families()
#> [1] "weibull" "powerlindley" "explindley" "expexponential"
#> [5] "moexponential" "lomax" "expteissier" "loglogistic"
#> [9] "chen" "lognormal" "gamma" "powermuth"fam <- slt_dist("weibull")
fam$p(1, lambda = 1, alpha = 2)
#> [1] 0.6321
fam$q(0.5, lambda = 1, alpha = 2)
#> [1] 0.8326| Family | alpha = 1 reduces to |
|---|---|
weibull |
Exponential |
expexponential |
Exponential |
moexponential |
Exponential |
gamma |
Exponential |
powerlindley |
Lindley |
explindley |
Lindley (same limit as powerlindley) |
lomax |
(boundary member of the Lomax family) |
expteissier |
baseline Teissier |
powermuth |
baseline Teissier (same limit as expteissier) |
loglogistic |
Log-Logistic, shape 1 |
chen |
Chen, shape 1 |
lognormal |
Log-normal, log-sd 1 |
case = "shape1"/"shape11" (Section 1.2)
fixes the elevated-stage shape parameter to exactly 1 – as the table
shows, this only makes the elevated stage Exponential for
weibull, expexponential,
moexponential, and gamma.
powerlindley, expexponential,
lomax, and expteissier are the paper’s own
baseline-stage extension points; the remaining seven families are this
package’s own additions, covering hazard shapes not available among the
first four (a non-monotonic hazard for loglogistic; a
bathtub-shaped hazard for chen;
gamma/lognormal, two of the most standard
lifetime distributions;
explindley/moexponential, the “exponentiate
the cdf” and “tilt parameter” siblings of
powerlindley/expexponential respectively). See
?slt_dist for the pdf/cdf and literature reference of
each.
With \theta_0 = (\lambda_0, \alpha_0) at the baseline
stage and \theta_1 = (\lambda_1, \alpha_1) at the elevated
stage, four parameter-sharing structures are logically possible. This
package supports three of them:
slt_cases()
#> case n_par parameters
#> 1 common 3 lambda0, lambda1, alpha
#> 2 shape1 3 lambda0, alpha0, lambda1
#> 3 shape11 2 lambda0, lambda1
#> description
#> 1 theta0=(lambda0,alpha), theta1=(lambda1,alpha) [shared shape]
#> 2 theta0=(lambda0,alpha0), theta1=(lambda1,1) [stage-1 shape fixed at 1]
#> 3 theta0=(lambda0,1), theta1=(lambda1,1) [both shapes fixed at 1]The fourth, fully unrestricted structure (\alpha_0 and
\alpha_1 both free, 4 parameters) is not
offered: with a single change-point and no replicated stress levels,
that structure is empirically non-identifiable – the profile
log-likelihood in (\alpha_0, \alpha_1) is extremely flat,
producing unstable estimates and frequent optimiser non-convergence.
"shape1" (baseline shape free, elevated shape fixed at 1)
is the structure most useful as a primary working model;
"shape11" (both shapes fixed at 1) is its natural nested
null, used by [slt_lrt()]; "common" (a single
shared shape, both scales free) is a well-identified alternative.
[slt_reduce_params()] converts a full
(theta0, theta1) pair into a case’s free parameter vector –
mostly useful in simulation studies, to put a known “true” parameter set
into the same format fit_slt() returns, for comparing
against the fitted par:
The classical simple-step-stress special case
(prop_transfer = 1):
set.seed(2026)
theta0 <- c(0.05, 1.5) # (lambda0, alpha0)
theta1 <- c(0.20, 1) # (lambda1, alpha1 = 1) -- consistent with case = "shape1"
tau1 <- slt_tau("weibull", theta0, p = 0.5) # change-point at the stage-0 median
tau1
#> [1] 5.771
d <- rslt(n = 200, family = "weibull", theta0 = theta0, theta1 = theta1, tau1 = tau1, prop_transfer = 1)
str(d)
#> List of 4
#> $ Y : num [1:112] 0.0831 0.192 0.2282 0.242 0.4735 ...
#> $ Z : num [1:88] 5.79 5.83 5.85 5.97 6.01 ...
#> $ n_early : int 112
#> $ n_transferred: int 88The general random-withdrawal case – the paper’s actual SLT model –
uses the same function with a smaller prop_transfer
("typeP", a target proportion) or
design = "typeM" (a target count):
d_palt <- rslt(n = 200, family = "weibull", theta0 = theta0, theta1 = theta1,
tau1 = tau1, design = "typeP", prop_transfer = 0.5)
str(d_palt)
#> List of 4
#> $ Y : num [1:149] 0.233 0.38 0.584 0.592 0.657 ...
#> $ Z : num [1:51] 5.94 5.94 6.02 6.05 6.06 ...
#> $ n_early : int 98
#> $ n_transferred: int 51
d_palt_m <- rslt(n = 200, family = "weibull", theta0 = theta0, theta1 = theta1,
tau1 = tau1, design = "typeM", R0_1 = 100)
str(d_palt_m)
#> List of 4
#> $ Y : num [1:100] 0.233 0.323 0.324 0.337 0.506 ...
#> $ Z : num [1:100] 5.8 5.81 5.83 5.83 5.88 ...
#> $ n_early : int 95
#> $ n_transferred: int 100fit <- fit_slt(d, family = "weibull", case = "shape1", tau1 = tau1)
fit
#> Two-stage lifetime model fit ('slt_fit')
#> Family : Weibull
#> Case : shape1
#> tau1 : 5.771
#> n : 200 (n0 = 112, n1 = 88)
#> logLik : -553 AIC: 1112 BIC: 1122
#>
#> Coefficients (natural scale):
#> Estimate Std. Error
#> lambda0 0.0749 0.0158
#> alpha0 1.3669 0.1182
#> lambda1 0.2200 0.0235
summary(fit)
#> Summary of two-stage lifetime model fit
#> Family : Weibull
#> Case : shape1
#> n = 200 logLik = -553.01 AIC = 1112.0201 BIC = 1121.915
#>
#> Coefficients (natural scale, 95% Wald log-normal CI):
#> Estimate Std. Error Lower Upper
#> lambda0 0.0749 0.0158 0.0495 0.1132
#> alpha0 1.3669 0.1182 1.1537 1.6194
#> lambda1 0.2200 0.0235 0.1786 0.2712
#>
#> theta0 (stage 0) = (0.0749, 1.3669)
#> theta1 (stage 1) = (0.22, 1)fit_slt() runs a Nelder-Mead warm start followed by BFGS
(with a numerical Hessian for inference) from several perturbed starting
values, keeping the converged fit with the highest log-likelihood – this
guards against both local optima and the occasional optimiser failure.
Standard S3 methods work as expected:
coef(fit)
#> lambda0 alpha0 lambda1
#> 0.07485 1.36688 0.22004
vcov(fit)
#> lambda0 alpha0 lambda1
#> lambda0 2.497e-04 -1.670e-03 3.238e-13
#> alpha0 -1.670e-03 1.398e-02 -2.312e-12
#> lambda1 3.238e-13 -2.312e-12 5.502e-04
logLik(fit)
#> 'log Lik.' -553 (df=3)
AIC(fit)
#> [1] 1112
BIC(fit)
#> [1] 1122One family-specific note: lomax’s shape parameter has a
notoriously high-variance MLE at small-to-moderate sample sizes (a well
known feature of the family, not a defect of the optimiser). If you plan
to fit family = "lomax", prefer larger samples and/or the
bootstrap (rather than the asymptotic normal) confidence intervals
below.
Asymptotic (Wald) intervals: type = "lognormal" (the
default) builds the interval on the log scale and exponentiates,
guaranteeing a positive interval; type = "normal" applies
the delta-method standard error directly on the natural scale and can
occasionally produce a negative lower bound for a
positive parameter, especially at small n:
confint(fit) # type = "lognormal" (default), always positive
#> 2.5% 97.5%
#> lambda0 0.04949 0.1132
#> alpha0 1.15375 1.6194
#> lambda1 0.17856 0.2712
confint(fit, type = "normal") # can occasionally go negative for small n
#> 2.5% 97.5%
#> lambda0 0.04388 0.1058
#> alpha0 1.13517 1.5986
#> lambda1 0.17407 0.2660Bootstrap alternatives – non-parametric (case resampling) and
parametric (simulate from the fitted model) – each with
percentile, bootstrap-t, and
log-scale bootstrap-t variants. The plain
bootstrap-t interval has the same occasional-negative-bound
issue as the natural-scale asymptotic interval above, for the same
reason (it is an ordinary linear pivot); the log-scale version applies
the identical pivot construction on log(theta) and
exponentiates, guaranteeing positivity, directly analogous to why
type = "lognormal" is preferred above. The percentile
interval is already always positive (it is built from quantiles of the
always-positive bootstrap estimates themselves).
b <- slt_bootstrap_ci(fit, B = 1000, method = "nonparametric")
b$percentile # always positive
b$boot_t # can occasionally go negative for small n, like type = "normal" above
b$log_boot_t # always positive, like type = "lognormal" above
slt_bootstrap_ci(fit, B = 1000, method = "parametric") # prop_transfer = 1 default
slt_bootstrap_ci(fit, B = 1000, method = "parametric", prop_transfer = 0.5) # genuine partial withdrawalThis section validates the package’s fidelity to the paper directly, and documents where the package’s inferential tools go beyond, or fall short of, the paper’s own results.
Table 2 of Laumen & Cramer (2019) gives a "typeP"
SLT sample (n=16, tau1=15, true
theta0=40, theta1=20, i.e. Exponential
means – see the parameterisation note in Section 1). Entering
that data directly and fitting the pure-Exponential model
(case = "shape11") recovers the paper’s own reported MLEs
exactly:
Y <- c(2.55, 7.77, 9.01, 9.23, 12.34, 18.61, 19.39, 27.54, 39.67, 43.25, 91.46)
Z <- c(24.51, 30.73, 36.88, 55.26, 65.39)
fit_paper <- fit_slt(list(Y = Y, Z = Z), family = "weibull", case = "shape11", tau1 = 15)
c(theta0_hat = 1 / fit_paper$par["lambda0"], theta1_hat = 1 / fit_paper$par["lambda1"])
#> theta0_hat.lambda0 theta1_hat.lambda1
#> 32.35 27.55
# Paper reports: theta0_hat = 32.35, theta1_hat = 27.55slt_prob_stage1()
(Lemma 4.1)The MLE of the elevated-stage parameter only exists when at least one
unit is actually transferred and fails there (R*_1 > 0).
slt_prob_stage1() implements the paper’s Lemma 4.1 for this
probability, and exactly reproduces the paper’s own Table 5:
slt_prob_stage1(12, 0.5, c(1, 1), design = "typeP", pi1 = 0.25) # paper: n*=8, prob=0.9864756680
#> $n
#> [1] 12
#>
#> $tau1
#> [1] 0.5
#>
#> $F0_tau1
#> [1] 0.3935
#>
#> $design
#> [1] "typeP"
#>
#> $pi1
#> [1] 0.25
#>
#> $R0_1
#> NULL
#>
#> $n_star
#> [1] 8
#>
#> $prob
#> [1] 0.9865
slt_prob_stage1(12, 0.5, c(1, 1), design = "typeM", R0_1 = 6) # paper: n*=11, prob=0.9999862301
#> $n
#> [1] 12
#>
#> $tau1
#> [1] 0.5
#>
#> $F0_tau1
#> [1] 0.3935
#>
#> $design
#> [1] "typeM"
#>
#> $pi1
#> NULL
#>
#> $R0_1
#> [1] 6
#>
#> $n_star
#> [1] 11
#>
#> $prob
#> [1] 1This is useful for planning: before running a real experiment, check
that your intended n, tau1, and
pi1/R0_1 give a comfortably high
prob under a plausible guess at theta0.
Because the reference distribution’s parameters were estimated from
the same data, the classical Kolmogorov-Smirnov p-value is
anti-conservative (the well known Lilliefors problem).
[slt_gof_ks()] reports both the naive value and a
parametric-bootstrap-corrected one:
"shape11" is nested in both "shape1" and
"common" (fixing the remaining free shape(s) to 1), giving
a likelihood-ratio test of H0: shape = 1:
fit0 <- fit_slt(d, "weibull", "shape11", tau1 = tau1)
slt_lrt(fit, fit0)
#> Likelihood-ratio test (Weibull): H1 = 'shape1' vs. H0 = 'shape11'
#> LR statistic = 11.6477, df = 1, p-value = 0.0006428For exploratory comparison across any set of family/case fits (not
necessarily nested), use [slt_model_comparison()]:
fitc <- fit_slt(d, "weibull", "common", tau1 = tau1)
slt_model_comparison(list("shape1" = fit, "shape11" = fit0, "common" = fitc))
#> model family case n_par logLik AIC BIC converged
#> 1 shape1 Weibull shape1 3 -553.0 1112 1122 TRUE
#> 2 common Weibull common 3 -553.5 1113 1123 TRUE
#> 3 shape11 Weibull shape11 2 -558.8 1122 1128 TRUEFour real step-stress data sets are bundled with the package (see
?slt_han_kundu_2014 and related help pages). Here we
compare all twelve baseline distributions under
case = "common" on the Han & Kundu (2014) data set
(case = "common" estimates a single shared shape rather
than fixing the elevated-stage shape at exactly 1, which suits an
across-family comparison better – see Section 1.2):
data(slt_han_kundu_2014)
d_real <- list(Y = slt_han_kundu_2014$y0, Z = slt_han_kundu_2014$y1)
tau1_real <- slt_han_kundu_2014$tau1
fits <- lapply(slt_families(), function(fam) {
fit_slt(d_real, family = fam, case = "common", tau1 = tau1_real, n_starts = 5)
})
names(fits) <- slt_families()
slt_model_comparison(fits)
#> model family case n_par logLik AIC BIC
#> 1 expteissier Exponentiated Teissier common 3 -184.3 374.6 378.9
#> 2 powermuth Power Muth (Power Teissier) common 3 -184.7 375.3 379.6
#> 3 weibull Weibull common 3 -185.0 376.1 380.4
#> 4 moexponential Marshall-Olkin Exponential common 3 -185.2 376.3 380.6
#> 5 explindley Exponentiated Lindley common 3 -185.3 376.7 381.0
#> 6 gamma Gamma common 3 -185.4 376.8 381.1
#> 7 expexponential Exponentiated Exponential common 3 -185.5 377.0 381.3
#> 8 powerlindley Power Lindley common 3 -185.6 377.2 381.5
#> 9 chen Chen (2000) common 3 -185.7 377.4 381.7
#> 10 lomax Lomax common 3 -186.3 378.6 382.9
#> 11 loglogistic Log-Logistic (Fisk) common 3 -187.7 381.4 385.7
#> 12 lognormal Log-normal common 3 -188.1 382.2 386.5
#> converged
#> 1 TRUE
#> 2 TRUE
#> 3 TRUE
#> 4 TRUE
#> 5 TRUE
#> 6 TRUE
#> 7 TRUE
#> 8 TRUE
#> 9 TRUE
#> 10 TRUE
#> 11 TRUE
#> 12 TRUEbest_fit <- fits[[slt_model_comparison(fits)$model[1]]]
summary(best_fit)
#> Summary of two-stage lifetime model fit
#> Family : Exponentiated Teissier
#> Case : common
#> n = 31 logLik = -184.3182 AIC = 374.6364 BIC = 378.9383
#>
#> Coefficients (natural scale, 95% Wald log-normal CI):
#> Estimate Std. Error Lower Upper
#> lambda0 0.0015 0.0004 0.0009 0.0024
#> lambda1 0.0162 0.0033 0.0108 0.0243
#> alpha 0.5476 0.1419 0.3295 0.9102
#>
#> theta0 (stage 0) = (0.0015, 0.5476)
#> theta1 (stage 1) = (0.0162, 0.5476)
plot_cdf(best_fit)Not every family need converge for every case/data set: a fixed
elevated-stage shape of exactly 1
(case = "shape1"/"shape11") can be a poor
match for a family whose shape parameter’s natural scale depends on the
data (e.g. chen, where the shape is an exponent on the
failure time feeding directly into an exponential), in which case
[slt_model_comparison()] reports
converged = FALSE/NA for that family rather
than a misleading result; trying case = "common", as above,
is a reasonable first thing to check.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.