| Title: | A Unified, Extensible Toolkit for Time-to-Event Analysis |
|---|---|
| Description: | One clean interface over the established survival stack (parametric accelerated-failure-time models, Cox proportional hazards, competing risks, recurrent events, frailty, flexible splines and a non-parametric Kaplan-Meier baseline), driven by an extensible method registry so new estimators slot in without an API change. Fits return a single typed object with consistent prediction, summary and tidying methods. On top of the fits sit the value layer: cross-method triangulation that reads disagreement as a misspecification signal, restricted mean survival time and cumulative incidence, inverse-probability-of-censoring-weighted predictive scoring, a small-sample power gate that abstains when events are too few to identify the model, a registry conformance contract, and an optional emitter to an ensemble-manifest contract for composition with a wider analytics stack. |
| Authors: | Max Moldovan [aut, cre] (ORCID: <https://orcid.org/0000-0001-9680-8474>) |
| Maintainer: | Max Moldovan <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-14 11:42:08 UTC |
| Source: | https://github.com/max578/survkit |
Produce a draw ensemble for orchestra composition. Coefficients are drawn from
their Gaussian sampling approximation (mean = estimate, covariance = vcov),
and the result is shaped to the ensemble-manifest contract (a parameter draw
frame with provenance) so a pesto_ensemble_manifest-compatible adapter can
consume it.
as_survkit_manifest( fit, n_draws = 200L, times = NULL, newdata = NULL, seed = NULL )as_survkit_manifest( fit, n_draws = 200L, times = NULL, newdata = NULL, seed = NULL )
fit |
A survkit_fit. |
n_draws |
Integer number of draws (default |
times |
Optional numeric time grid for the survival outputs. |
newdata |
Optional single covariate profile (one row) for the survival outputs. Required for the per-draw survival ensemble. |
seed |
Optional integer RNG seed (recorded in the manifest). |
When times and a single-profile newdata are given and the fit is
parametric, spline or cure, the outputs slot carries a genuine per-draw
survival ensemble: the draws come from the backend's own sampling
distribution and each draw's survival is evaluated through the fitted
distribution function, so params and outputs share the same draws. For a
Cox-family or non-parametric fit a per-draw survival ensemble would also need
the baseline-hazard uncertainty, so outputs instead holds the
maximum-likelihood survival curve marked with draw = 0.
A survkit_manifest object.
survkit_manifest for the returned class, survkit() for the fit.
fit <- survkit(survival::Surv(time, status) ~ age, survival::lung, method = "weibull") m <- as_survkit_manifest(fit, n_draws = 50L, seed = 1L) nrow(m@params)fit <- survkit(survival::Surv(time, status) ~ age, survival::lung, method = "weibull") m <- as_survkit_manifest(fit, n_draws = 50L, seed = 1L) nrow(m@params)
Is an object a survkit power-gate refusal?
is_survkit_refusal(x)is_survkit_refusal(x)
x |
Any object. |
A single logical.
Other model-fitting:
survkit(),
survkit_cuminc(),
survkit_power(),
survkit_refusal(),
survkit_rmst(),
survkit_score(),
survkit_triangulate()
is_survkit_refusal(42)is_survkit_refusal(42)
Delegate to stats::predict() on the backend object underlying a
survkit_fit (e.g. predict.coxph(), predict.survreg()), passing ...
straight through. For a backend-independent survival, hazard or quantile
prediction on a common time grid, use survkit_curve() instead.
object |
A survkit_fit. |
... |
Passed to the backend's |
Whatever the backend's predict method returns.
survkit_curve() for a backend-independent prediction grid.
fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") head(predict(fit, type = "lp"))fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") head(predict(fit, type = "lp"))
One interface over the established survival stack. method selects an
estimator from the registry (survkit_methods()); the appropriate backend is
checked, a small-sample power gate runs (survkit_power()), and the fit is
returned as a single typed object (survkit_fit) with consistent print,
summary, coef, vcov, predict and tidy() methods.
survkit( formula, data, method = "weibull", ..., check_power = TRUE, warn_underpowered = TRUE, on_underpowered = c("warn", "abstain") )survkit( formula, data, method = "weibull", ..., check_power = TRUE, warn_underpowered = TRUE, on_underpowered = c("warn", "abstain") )
formula |
A model formula, e.g. |
data |
A data frame. |
method |
Character registry key (default |
... |
Passed to the backend estimator. |
check_power |
Logical; run the events-per-variable gate (default |
warn_underpowered |
Logical; warn when the gate flags the model
under-powered (default |
on_underpowered |
One of |
The left-hand side of formula is a survival::Surv() response. Extra
arguments in ... pass straight to the backend estimator, so any backend
option remains reachable.
A survkit_fit object, or a survkit_refusal() when
on_underpowered = "abstain" and the power gate is not satisfied.
survkit_methods() for the registry, survkit_power() for the gate.
Other model-fitting:
is_survkit_refusal(),
survkit_cuminc(),
survkit_power(),
survkit_refusal(),
survkit_rmst(),
survkit_score(),
survkit_triangulate()
df <- survival::lung fit <- survkit(survival::Surv(time, status) ~ age + sex, df, method = "weibull") fit coef(fit)df <- survival::lung fit <- survkit(survival::Surv(time, status) ~ age + sex, df, method = "weibull") fit coef(fit)
Return the field-level contract that every registered fit closure must
honour: the names of the fields a normalised fit result carries, so that
survkit() and every downstream verb can rely on one shape. Use
survkit_validate_method() to check a specific method against it.
survkit_contract()survkit_contract()
A character vector of the required field names.
survkit_validate_method(), survkit_register().
Other method-registry:
survkit_methods(),
survkit_register(),
survkit_validate_method()
survkit_contract()survkit_contract()
The Aalen-Johansen estimator of the cumulative incidence function for each
competing event, computed from a multi-state survival::survfit(). Unlike one
minus a cause-specific Kaplan-Meier, this accounts for the competing events
and so sums, across causes, to the overall failure probability.
survkit_cuminc(formula, data, ...)survkit_cuminc(formula, data, ...)
formula |
A model formula whose response is a multi-state
|
data |
A data frame. |
... |
Passed to |
A data frame with time, group (the stratum, or "all"),
cause, cif (the cumulative incidence) and cif_se (its standard error).
survkit() with method = "fine_gray" for a regression on the
subdistribution hazard.
Other model-fitting:
is_survkit_refusal(),
survkit(),
survkit_power(),
survkit_refusal(),
survkit_rmst(),
survkit_score(),
survkit_triangulate()
mg <- survival::mgus2 mg$etime <- with(mg, ifelse(pstat == 1, ptime, futime)) mg$event <- with(mg, factor(ifelse(pstat == 1, "pcm", ifelse(death == 1, "death", "censor")), levels = c("censor", "pcm", "death"))) ci <- survkit_cuminc(survival::Surv(etime, event) ~ 1, mg) head(ci)mg <- survival::mgus2 mg$etime <- with(mg, ifelse(pstat == 1, ptime, futime)) mg$event <- with(mg, factor(ifelse(pstat == 1, "pcm", ifelse(death == 1, "death", "censor")), levels = c("censor", "pcm", "death"))) ci <- survkit_cuminc(survival::Surv(etime, event) ~ 1, mg) head(ci)
Backend-aware predictions over a time grid for one or more covariate
profiles. Parametric, spline and cure fits use the backend's own distribution
function and support every type; Cox-family and non-parametric fits use
survival::survfit() and support the survival curve.
survkit_curve( fit, newdata = NULL, times = NULL, type = c("survival", "hazard", "cumhaz", "quantile") )survkit_curve( fit, newdata = NULL, times = NULL, type = c("survival", "hazard", "cumhaz", "quantile") )
fit |
A survkit_fit. |
newdata |
A data frame of covariate profiles. The default is the backend's reference profile. |
times |
Numeric times at which to evaluate. The default is an automatic grid from the backend. |
type |
Character quantity to predict: |
A data frame with time, value (named for type when returned by
the backend) and a profile index.
survkit_tidy() for the coefficient table, survkit_rmst() for the
restricted mean.
Other fit-methods:
survkit_tidy()
fit <- survkit(survival::Surv(time, status) ~ age, survival::lung, method = "weibull") head(survkit_curve(fit, times = c(100, 300, 500)))fit <- survkit(survival::Surv(time, status) ~ age, survival::lung, method = "weibull") head(survkit_curve(fit, times = c(100, 300, 500)))
An S7 object returned by survkit(). It normalises every backend's output to
one shape: the method and kind, the raw backend fit (kept for backend-specific
follow-up), the coefficient vector and covariance, the log-likelihood, the
sample and event counts, and the small-sample power verdict.
survkit_fit( method = character(0), kind = character(0), backend = character(0), fit = NULL, coefficients = integer(0), vcov = NULL, loglik = NA_real_, n = integer(0), n_events = integer(0), ratio_type = NA_character_, aux_pars = character(0), power = list(), formula = NULL, call = NULL )survkit_fit( method = character(0), kind = character(0), backend = character(0), fit = NULL, coefficients = integer(0), vcov = NULL, loglik = NA_real_, n = integer(0), n_events = integer(0), ratio_type = NA_character_, aux_pars = character(0), power = list(), formula = NULL, call = NULL )
method |
Character method name (a registry key, e.g. |
kind |
Character method family: one of |
backend |
Character name of the package that produced the fit. |
fit |
The raw backend fit object. |
coefficients |
Named numeric coefficient vector. |
vcov |
Coefficient covariance matrix (or |
loglik |
Numeric log-likelihood (or |
n |
Integer number of observations. |
n_events |
Integer number of events (non-censored). |
ratio_type |
Character code for how an exponentiated covariate
coefficient reads: |
aux_pars |
Character names of the baseline distribution parameters (the auxiliary parameters the tidier keeps out of the ratio column). |
power |
A |
formula |
The model formula. |
call |
The originating call. |
A survkit_fit S7 object.
survkit() (constructs this object), survkit_tidy(),
survkit_curve() (consume it).
fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") fit@method fit@n_eventsfit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") fit@method fit@n_events
A self-contained, manifest-compatible emission for orchestra composition: a
draw ensemble of parameters and predicted survival, with provenance. Produced
by as_survkit_manifest(); convertible to a pesto_ensemble_manifest when
that contract is available (see the manifest emitter).
survkit_manifest( params = data.frame(), outputs = NULL, time_grid = numeric(0), method = character(0), emitter_version = character(0), seed = NA_integer_ )survkit_manifest( params = data.frame(), outputs = NULL, time_grid = numeric(0), method = character(0), emitter_version = character(0), seed = NA_integer_ )
params |
Data frame of parameter draws ( |
outputs |
Data frame of predicted survival draws on a time grid. |
time_grid |
Numeric vector of evaluation times. |
method |
Character method name. |
emitter_version |
Character package version that emitted the manifest. |
seed |
Integer RNG seed. |
A survkit_manifest S7 object.
as_survkit_manifest(), which constructs this object.
fit <- survkit(survival::Surv(time, status) ~ age, survival::lung, method = "weibull") man <- as_survkit_manifest(fit, n_draws = 50L) man@methodfit <- survkit(survival::Surv(time, status) ~ age, survival::lung, method = "weibull") man <- as_survkit_manifest(fit, n_draws = 50L) man@method
List the registered methods
survkit_methods()survkit_methods()
A data frame of method, kind, backend, available (is the
backend installed) and note.
survkit_register() to add a method.
Other method-registry:
survkit_contract(),
survkit_register(),
survkit_validate_method()
survkit_methods()survkit_methods()
Assess whether a survival model is identifiable from the available events.
Returns the event count, the predictor count, the events-per-variable ratio
and a verdict. survkit() attaches this to every fit and warns when a model
is under-powered.
survkit_power(formula, data, min_epv = 10)survkit_power(formula, data, min_epv = 10)
formula |
A model formula with a |
data |
A data frame. |
min_epv |
Numeric events-per-variable floor (default |
The event count comes from the last column of the survival::Surv() response.
When that column is a multi-state factor (competing risks) the event count
cannot be read as a single 0/1 flag, so the verdict is "unknown" rather than
a guess. For a counting-process response (recurrent events) the count is the
number of event rows, not the number of distinct subjects.
A list: n, n_events, n_predictors, events_per_variable,
min_epv, underpowered (logical), verdict ("ok" / "underpowered" /
"unknown") and advice.
Peduzzi P, Concato J, Kemper E, Holford TR, Feinstein AR. A simulation study of the number of events per variable in logistic regression analysis. Journal of Clinical Epidemiology 1996; 49(12): 1373-1379. doi:10.1016/S0895-4356(96)00236-3
survkit(), which runs this gate on every fit.
Other model-fitting:
is_survkit_refusal(),
survkit(),
survkit_cuminc(),
survkit_refusal(),
survkit_rmst(),
survkit_score(),
survkit_triangulate()
df <- data.frame(time = rexp(40), status = rbinom(40, 1, 0.3), x1 = rnorm(40), x2 = rnorm(40)) survkit_power(survival::Surv(time, status) ~ x1 + x2, df)$verdictdf <- data.frame(time = rexp(40), status = rbinom(40, 1, 0.3), x1 = rnorm(40), x2 = rnorm(40)) survkit_power(survival::Surv(time, status) ~ x1 + x2, df)$verdict
Construct the typed "will not fit" token survkit() returns when
on_underpowered = "abstain" and the events-per-variable gate
(survkit_power()) flags the model as under-powered. Not signalled as a
condition – returned as an ordinary value, so a caller inspects it with
is_survkit_refusal() rather than a tryCatch().
survkit_refusal(power)survkit_refusal(power)
power |
A power-gate result from |
A classed list with class c("survkit_refusal", "orchestra_refusal", "error", "condition") and elements reason, n, n_events,
n_predictors, events_per_variable, min_epv, underpowered
(always TRUE), message.
survkit(), survkit_power(), is_survkit_refusal().
Other model-fitting:
is_survkit_refusal(),
survkit(),
survkit_cuminc(),
survkit_power(),
survkit_rmst(),
survkit_score(),
survkit_triangulate()
df <- data.frame(time = rexp(20), status = rbinom(20, 1, 0.2), x1 = rnorm(20), x2 = rnorm(20)) p <- survkit_power(survival::Surv(time, status) ~ x1 + x2, df) r <- survkit_refusal(p) is_survkit_refusal(r)df <- data.frame(time = rexp(20), status = rbinom(20, 1, 0.2), x1 = rnorm(20), x2 = rnorm(20)) p <- survkit_power(survival::Surv(time, status) ~ x1 + x2, df) r <- survkit_refusal(p) is_survkit_refusal(r)
Add (or override) an estimator in the method registry. The fit closure
receives (formula, data, ...) and must return a list with raw (the backend
fit), coef, vcov, loglik, n, n_events, kind and backend –
build it with the package's internal normaliser or by hand.
survkit_register(name, kind, backend, fit, note = "")survkit_register(name, kind, backend, fit, note = "")
name |
Character key, e.g. |
kind |
Character family: |
backend |
Character name of the backend package the |
fit |
A function |
note |
Character one-line description (shown by |
Invisibly, the method name.
survkit_methods() to list what is registered.
Other method-registry:
survkit_contract(),
survkit_methods(),
survkit_validate_method()
# register a trivial exponential alias backed by survival::survreg survkit_register("exp_survreg", "parametric", "survival", fit = function(formula, data, ...) { raw <- survival::survreg(formula, data = data, dist = "exponential", ...) list(raw = raw, coef = stats::coef(raw), vcov = stats::vcov(raw), loglik = as.numeric(stats::logLik(raw)), n = nrow(data), n_events = NA_integer_, kind = "parametric", backend = "survival") }) "exp_survreg" %in% survkit_methods()$method# register a trivial exponential alias backed by survival::survreg survkit_register("exp_survreg", "parametric", "survival", fit = function(formula, data, ...) { raw <- survival::survreg(formula, data = data, dist = "exponential", ...) list(raw = raw, coef = stats::coef(raw), vcov = stats::vcov(raw), loglik = as.numeric(stats::logLik(raw)), n = nrow(data), n_events = NA_integer_, kind = "parametric", backend = "survival") }) "exp_survreg" %in% survkit_methods()$method
The restricted mean survival time (RMST) to a horizon tau: the area under
the survival curve on [0, tau], a decision-relevant summary that stays
defined when the median is not reached. Parametric, spline and cure fits use
the backend's own RMST with its delta-method interval; Cox-family and
non-parametric fits use the area under survival::survfit() with its standard
error.
survkit_rmst(fit, tau, newdata = NULL)survkit_rmst(fit, tau, newdata = NULL)
fit |
A survkit_fit. |
tau |
Numeric horizon (a single positive time) the mean is restricted to. |
newdata |
A data frame of covariate profiles for the model-based fits. The default is the backend's reference profile. |
where is the (model-based or Kaplan-Meier) survival function.
Restricting the integral to keeps the summary defined and
identifiable from the observed follow-up even when the survival curve
never crosses one-half.
A data frame with tau, group (or profile), rmst, se,
conf_low and conf_high.
survkit_curve() for the curve the mean integrates.
Other model-fitting:
is_survkit_refusal(),
survkit(),
survkit_cuminc(),
survkit_power(),
survkit_refusal(),
survkit_score(),
survkit_triangulate()
fit <- survkit(survival::Surv(time, status) ~ 1, survival::lung, method = "km") survkit_rmst(fit, tau = 365)fit <- survkit(survival::Surv(time, status) ~ 1, survival::lung, method = "km") survkit_rmst(fit, tau = 365)
Evaluate a fitted model's predictions at one or more horizons: the concordance index (discrimination) and the inverse-probability-of-censoring-weighted Brier score with its index of prediction accuracy (calibration and accuracy against a covariate-free Kaplan-Meier reference).
survkit_score(fit, data, times)survkit_score(fit, data, times)
fit |
A survkit_fit with a right-censored |
data |
A data frame carrying the response and covariates to score on (in-sample if it is the training data, out-of-sample otherwise). |
times |
Numeric horizons at which to score. |
The inverse-probability-of-censoring-weighted Brier score at horizon
is
where is the predicted survival probability,
is the Kaplan-Meier estimator of the censoring survival
function, and the index of prediction accuracy is
against a covariate-free reference
.
A data frame with time, cindex (Harrell's C using predicted risk
at that horizon), brier (IPCW Brier) and ipa (index of prediction
accuracy).
Graf E, Schmoor C, Sauerbrei W, Schumacher M. Assessment and comparison of prognostic classification schemes for survival data. Statistics in Medicine 1999; 18(17-18): 2529-2545. doi:10.1002/(SICI)1097-0258(19990915/30)18:17/18<2529::AID-SIM274>3.0.CO;2-5
survkit_curve() for the predictions scored here.
Other model-fitting:
is_survkit_refusal(),
survkit(),
survkit_cuminc(),
survkit_power(),
survkit_refusal(),
survkit_rmst(),
survkit_triangulate()
fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") survkit_score(fit, survival::lung, times = c(200, 400, 600))fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") survkit_score(fit, survival::lung, times = c(200, 400, 600))
Return the coefficient table with standard errors, the exponentiated effect
and Wald confidence intervals. Covariate rows and baseline distribution
parameters are separated by a component column, and the ratio_type column
records whether a covariate effect reads as a hazard ratio (proportional
hazards) or a time ratio (accelerated failure time). Auxiliary parameters (a
log-scale, a shape) are never exponentiated into the ratio column, so a
parametric fit no longer reports a meaningless "ratio" for its scale.
survkit_tidy(fit, conf_level = 0.95)survkit_tidy(fit, conf_level = 0.95)
fit |
A survkit_fit. |
conf_level |
Confidence level for the Wald interval (default |
A data frame with columns term, component
("covariate" / "auxiliary"), estimate, std_error, ratio_type,
ratio, conf_low and conf_high. For auxiliary parameters ratio_type,
ratio and the interval are NA.
survkit_curve() for predicted survival.
Other fit-methods:
survkit_curve()
fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") survkit_tidy(fit)fit <- survkit(survival::Surv(time, status) ~ age + sex, survival::lung, method = "cox") survkit_tidy(fit)
Fit the same data under several methods and compare them on the restricted
mean survival time (and, if a landmark time is given, on survival at that
time). The relative spread across methods is a model-misspecification signal:
when the methods disagree by more than threshold, the fit is flagged.
survkit_triangulate( formula, data, methods = c("weibull", "cox", "km"), tau = NULL, time_star = NULL, newdata = NULL, threshold = 0.1, ... )survkit_triangulate( formula, data, methods = c("weibull", "cox", "km"), tau = NULL, time_star = NULL, newdata = NULL, threshold = 0.1, ... )
formula |
A model formula with a |
data |
A data frame. |
methods |
Character vector of registry keys to compare (default
|
tau |
Numeric horizon for the restricted mean. The default is the 90th percentile of the observed times. |
time_star |
Optional landmark time; when given, survival at |
newdata |
Optional single covariate profile for the model-based quantities. |
threshold |
Numeric relative-spread threshold above which the methods are
flagged as disagreeing (default |
... |
Passed to each |
A survkit_triangulation list with the per-method quantities, the
disagreement summary, and a logical flagged. It has a print method.
survkit_rmst() for the quantity compared, survkit() for a single
fit.
Other model-fitting:
is_survkit_refusal(),
survkit(),
survkit_cuminc(),
survkit_power(),
survkit_refusal(),
survkit_rmst(),
survkit_score()
tri <- survkit_triangulate(survival::Surv(time, status) ~ age + sex, survival::lung, methods = c("weibull", "cox", "km"), tau = 500) tritri <- survkit_triangulate(survival::Surv(time, status) ~ age + sex, survival::lung, methods = c("weibull", "cox", "km"), tau = 500) tri
Fit a registered method on the supplied data and check that its normalised
result honours the registry contract (survkit_contract()): every required
field is present and of the right type. When the method's backend is not
installed the check is skipped rather than failed.
survkit_validate_method(name, formula, data, ...)survkit_validate_method(name, formula, data, ...)
name |
Character registry key to validate. |
formula |
A model formula appropriate for the method (competing-risks and recurrent methods need the matching multi-state or counting-process response). |
data |
A data frame to fit on. |
... |
Passed to the method's |
A list with method, ok (TRUE / FALSE, or NA when skipped),
missing (any absent fields), failed (fields failing their type check)
and reason (why it was skipped, if it was).
survkit_contract() for the contract, survkit_register() to add a
method.
Other method-registry:
survkit_contract(),
survkit_methods(),
survkit_register()
survkit_validate_method("cox", survival::Surv(time, status) ~ age, survival::lung)survkit_validate_method("cox", survival::Surv(time, status) ~ age, survival::lung)