Cause-specific Cox proportional-hazards model for competing risks.
CauseSpecificCox(
cause,
*,
ties="efron",
conf_level=0.95,
)
In a competing-risks setting, a cause-specific hazard model answers “among subjects still event-free, what drives the rate of this particular event?” It does so by treating competing events as censoring: subjects who experience a different cause are removed from the risk set at the time of their competing event, and a standard Cox model is fitted on the re-coded data.
This wrapper takes a multi-state Surv response and a target cause, automatically re-codes the competing events as censored, and delegates to CoxPH. All CoxPH features (stratification, frailty, robust standard errors, diagnostics, prediction) are available on the fitted object.
Parameters
cause: Any
-
The cause of interest. Can be a state label (string) matching one of the states in the Surv response, or an integer cause code (1-indexed).
ties: str = "efron"
-
Tie-handling method passed to CoxPH: "efron" (default) or "breslow".
conf_level: float = 0.95
-
Confidence level for coefficient intervals (default 0.95).
Examples
Fit a cause-specific Cox model for PCM progression in the mgus2 dataset:
import greenwood as gw
mg = gw.load_dataset("mgus2", backend="polars")
cr = gw.Outcome.first_event(
endpoints={"pcm": ("ptime", "pstat"), "death": ("futime", "death")}
)
csc = gw.CauseSpecificCox(cause="pcm").fit(cr, covariates=["age", "sex"], data=mg)
csc
CauseSpecificCox (cause-specific Cox model, cause='pcm', ties='efron')
coef exp(coef) se(coef) z p
age 0.01304 1.013 0.008259 1.579 0.1144
sexM -0.02514 0.9752 0.1885 -0.133 0.8939
n = 1384, events = 115
Likelihood ratio test = 2.682 on 2 df, p = 0.2616
Compare cause-specific hazard ratios for both causes side by side:
csc_death = gw.CauseSpecificCox(cause="death").fit(cr, covariates=["age", "sex"], data=mg)
gw.tidy(csc, exponentiate=True, format="polars")
shape: (2, 7)| term | estimate | std_error | statistic | p_value | conf_low | conf_high |
|---|
| str | f64 | f64 | f64 | f64 | f64 | f64 |
| "age" | 1.013124 | 0.008259 | 1.578771 | 0.114389 | 0.996857 | 1.029657 |
| "sexM" | 0.975176 | 0.188456 | -0.133388 | 0.893886 | 0.674014 | 1.410902 |
Methods
|
Name
|
Description
|
|
fit()
|
Fit the cause-specific Cox model.
|
fit()
Fit the cause-specific Cox model.
fit(
surv,
covariates=None,
*,
data=None,
strata=None,
robust=False,
cluster=None,
frailty=None,
frailty_cluster=None,
frailty_theta=0.5,
frailty_max_iter=30,
max_iter=30,
tol=1e-09,
weights=None,
)
Re-codes the multi-state response so that the target cause is treated as the event and all competing causes are treated as censored, then fits a standard CoxPH model on the re-coded data.
Parameters
surv: Surv | Outcome | str
-
A multi-state response: a Surv with a categorical event, an Outcome (such as gw.Outcome.first_event(...)), or a formula string such as "Surv(etime, factor(cause, c(0, 1, 2), c('censor', 'pcm', 'death'))) ~ age + sex". An Outcome or formula reads its columns from data. The formula’s right-hand side sets covariates.
covariates: Any = None
-
A dataframe or 2-D array of covariates. A list of column names in data also works.
data: Any = None
-
A data frame (pandas, Polars, PyArrow, DuckDB, a lazy frame, …) holding the columns named by the response, strata, cluster, frailty_cluster, and covariates. When surv is an Outcome or a formula, rows with a missing value in any column used are dropped before fitting. Covariate formula strings and lists of column names are also resolved here.
strata: Any = None
-
Passed through to CoxPH.fit().
robust: Any = None
-
Passed through to CoxPH.fit().
cluster: Any = None
-
Passed through to CoxPH.fit().
frailty: Any = None
-
Passed through to CoxPH.fit().
frailty_cluster: Any = None
-
Passed through to CoxPH.fit().
frailty_theta: Any = None
-
Passed through to CoxPH.fit().
frailty_max_iter: Any = None
-
Passed through to CoxPH.fit().
max_iter: int = 30
-
Newton-Raphson iteration control passed through to CoxPH.fit().
tol: int = 30
-
Newton-Raphson iteration control passed through to CoxPH.fit().
weights: Any = None
-
Case weights, one per row (a column name in
data, or an array). Must be finite and strictly positive. Default is None (all weights 1).
Returns
CauseSpecificCox
-
The fitted estimator.
Examples
Fit a cause-specific Cox model for plasma-cell malignancy (pcm) in the mgus2 dataset. Competing events (death) are treated as censored:
import greenwood as gw
mg = gw.load_dataset("mgus2", backend="pandas")
cr = gw.Outcome.first_event(
endpoints={"pcm": ("ptime", "pstat"), "death": ("futime", "death")}
)
csc = gw.CauseSpecificCox(cause="pcm").fit(
cr, covariates=["age", "sex"], data=mg
)
csc
CauseSpecificCox (cause-specific Cox model, cause='pcm', ties='efron')
coef exp(coef) se(coef) z p
age 0.01304 1.013 0.008259 1.579 0.1144
sexM -0.02514 0.9752 0.1885 -0.133 0.8939
n = 1384, events = 115
Likelihood ratio test = 2.682 on 2 df, p = 0.2616
Exponentiated coefficients give cause-specific hazard ratios:
gw.tidy(csc, exponentiate=True, format="polars")
shape: (2, 7)| term | estimate | std_error | statistic | p_value | conf_low | conf_high |
|---|
| str | f64 | f64 | f64 | f64 | f64 | f64 |
| "age" | 1.013124 | 0.008259 | 1.578771 | 0.114389 | 0.996857 | 1.029657 |
| "sexM" | 0.975176 | 0.188456 | -0.133388 | 0.893886 | 0.674014 | 1.410902 |