3.5 Parametric models in software

Software 3.5.1 (The exponential fit by hand). Example 3.2.2: the number of deaths and total follow-up, the estimated rate and its standard error per year, the \(95\%\) interval on the log scale, and the fitted mean and median in days:

> library(survival)
> t <- lung$time; d <- as.numeric(lung$status == 2)
> c(deaths = sum(d), total_days = sum(t))
    deaths total_days
       165      69593
> lam <- sum(d) / sum(t); se <- lam / sqrt(sum(d))     # MLE and its SE
> round(c(rate_per_year = 365.25 * lam, se = 365.25 * se), 4)
rate_per_year            se
       0.8660        0.0674
> ci <- exp(log(lam) + c(-1, 1) * 1.96 / sqrt(sum(d)))  # CI on the log scale
> round(365.25 * ci, 4)
[1] 0.7434 1.0087
> round(c(mean_days = 1 / lam, median_days = log(2) / lam), 1)
  mean_days median_days
      421.8       292.4

Reading the output. The rate is \(0.866\) deaths per person-year (s.e. \(0.067\)), with interval \((0.743, 1.009)\); the fitted median survival is \(292\) days.

Python: the same arithmetic; lifelines.ExponentialFitter().fit(t, d) gives the fitted mean, \(1/\hat \lambda \), as lambda_.

Software 3.5.2 (Four families by survreg). The exponential, Weibull, log-normal and log-logistic models fitted with survreg, their log-likelihoods and AICs; the Weibull’s location and scale and their translation to \(k\) and \(\lambda \); and the likelihood ratio test of \(k = 1\):

> fits <- lapply(c("exponential", "weibull", "lognormal", "loglogistic"),
+                function(dist) survreg(Surv(time, status) ~ 1, data = lung,
+                                       dist = dist))
> names(fits) <- c("exponential", "weibull", "lognormal", "loglogistic")
> round(sapply(fits, function(f) c(logLik = f$loglik[1], AIC = AIC(f))), 2)
       exponential  weibull lognormal loglogistic
logLik    -1162.34 -1153.85  -1169.27    -1160.93
AIC        2326.68  2311.70   2342.54     2325.86
> w <- fits$weibull
> c(intercept = unname(coef(w)), scale = w$scale)      # log T = mu + sigma W
intercept     scale
6.0349039 0.7593936
> round(c(shape_k = 1 / w$scale, lambda_days = exp(coef(w))[[1]]), 3)
    shape_k lambda_days
      1.317     417.759
> lr <- 2 * (w$loglik[1] - fits$exponential$loglik[1])
> round(c(LR = lr, p = pchisq(lr, 1, lower.tail = FALSE)), 5)  # is k = 1?
      LR        p
16.97398  0.00004

Reading the output. The Weibull has the largest log-likelihood among the two-parameter models and the smallest AIC. Its scale \(\hat \sigma = 0.759\) gives \(\hat k = 1/0.759 = 1.32\), and its intercept \(6.035\) gives \(\hat \lambda = e^{6.035} = 418\) days. The test of \(k = 1\) gives \(\chi ^2_1 = 17.0\), \(p = 0.00004\).

Python: lifelines.WeibullFitter, LogNormalFitter, LogLogisticFitter, each with an AIC_ attribute.

Software 3.5.3 (The Weibull likelihood by hand). The censored Weibull log-likelihood of the subsection on the Weibull family, maximised with optim over \((\log k, \log \lambda )\) so that both stay positive; the standard errors from the inverse Hessian; and the fitted median \(\lambda (\log 2)^{1/k}\):

> nll <- function(p) {              # Weibull by hand, p = (log k, log lam)
+   k <- exp(p[1]); l <- exp(p[2])
+   -sum(d * (log(k) - log(l) + (k - 1) * log(t / l)) - (t / l)^k)
+ }
> o <- optim(c(0, log(300)), nll, hessian = TRUE)
> round(c(k = exp(o$par[1]), lambda = exp(o$par[2]), logLik = -o$value), 3)
        k    lambda    logLik
    1.316   417.723 -1153.851
> round(sqrt(diag(solve(o$hessian))), 4)   # SEs of log k and log lambda
[1] 0.0624 0.0591
> med <- exp(o$par[2]) * log(2)^(1 / exp(o$par[1])); round(med, 1)
[1] 316.2

Reading the output. The hand-written likelihood reproduces survreg: \(\hat k = 1.316\), \(\hat \lambda = 418\) days, \(\ell = -1153.85\). The standard error of \(\log \hat k\) is \(0.062\), so \(\hat k\) is about \(1.32 \pm 0.16\), clearly above \(1\). The median is \(316\) days.

Python: scipy.optimize.minimize with the same function.

Questions on this section

Stuck on something here? Ask below and it stays attached to this topic.