Suppose you observe failure times from a Weibull distribution, but
some units are right-censored: you only know they survived past a
cutoff. Exact observations contribute log f(t) to the
log-likelihood while censored ones contribute log S(t).
Both share the same shape and scale parameters, but the math is
different for each row.
likelihood.contr handles this by letting you declare
each observation type’s contribution separately, then composing them
into a single model.
contr_name() generates a contribution from any R
distribution with d<name> and
p<name> functions. Four censoring types are
supported:
| Type | Log-likelihood contribution |
|---|---|
"exact" |
log f(x; theta) via d<name> |
"right" |
log S(x; theta) via
p<name>(lower.tail=FALSE) |
"left" |
log F(x; theta) via p<name> |
"interval" |
log [F(b; theta) - F(a; theta)] via
p<name> |
likelihood_contr() combines contributions and specifies
how to dispatch rows to the right contribution. Here
obs_type = "status" means the status column
determines which contribution handles each row:
model <- likelihood_contr(
obs_type = "status",
exact = exact,
right = right
)
model
#> Likelihood Contribution Model
#> -----------------------------
#> Observation types: exact, right
#> Dispatch method: column 'status'
#> Assumptions:
#> - iidThe contribution names (exact, right) must
match the values in the dispatch column.
The fit() generic returns a solver function. Call it
with data and starting values:
result <- suppressWarnings(
fit(model)(df, par = c(shape = 1.5, scale = 4))
)
summary(result)
#> Maximum Likelihood Estimate (Fisherian)
#> ----------------------------------------
#>
#> Coefficients:
#> Estimate Std. Error 2.5% 97.5%
#> shape 2.0672 0.1611 1.7514 2.383
#> scale 4.9571 0.2309 4.5046 5.410
#>
#> Log-likelihood: -383.9
#> AIC: 771.8
#> Number of observations: 300The result is a fisher_mle object with the usual
methods:
Every likelihood.model generic returns a closure. This
is useful for profiling or plotting:
When the observation type depends on multiple columns or a computed condition, pass a function instead of a column name:
model_fn <- likelihood_contr(
obs_type = function(df) ifelse(df$delta == 1, "exact", "right"),
exact = contr_name("exp", "exact", ob_col = "t"),
right = contr_name("exp", "right", ob_col = "t")
)
df_fn <- data.frame(t = c(0.5, 1.0, 2.0), delta = c(1, 0, 1))
loglik(model_fn)(df_fn, par = c(rate = 1.5))
#> [1] -4.43907For user-defined log-likelihood functions, analytical derivatives,
and model comparison via likelihood ratio tests, see
vignette("custom-contributions").