Compare cumulative incidence functions across groups using Gray’s test.
grays_test(
surv,
group,
*,
cause=1,
)
Gray’s test (1988) is the competing-risks analogue of the log-rank test. While the log-rank test compares overall survival across groups, Gray’s test compares the cumulative incidence function (CIF) for a specific cause across groups, properly accounting for competing events.
The test uses the subdistribution hazard framework: subjects who experience a competing event remain in the risk set with inverse-probability-of-censoring weights, reflecting the fact that they can no longer experience the target cause but still contribute information about its cumulative incidence.
Parameters
surv: Surv
-
A multi-state Surv response built with Surv.multistate(). Must have at least two causes. Event codes are 0 for censoring and 1..K for causes.
group: Any
-
Group labels, one per observation. Can be a Narwhals series, 1-D array, or Python sequence. Must have the same length as surv. At least two groups are required.
cause: int | str = 1
-
The cause of interest to compare across groups. Can be a state label (string) or an integer cause code (1-indexed). Default is
1 (the first cause).
Returns
TestResult
-
A result object with attributes:
statistic: Chi-square test statistic.
df: Degrees of freedom (number of groups minus one).
p_value: Upper-tail chi-square p-value.
method: "Gray's test" with the cause label.
observed: Dictionary mapping group labels to observed event counts.
expected: Dictionary mapping group labels to expected event counts.
Details
Gray’s test differs from the log-rank test applied to cause-specific hazards. The log-rank test on cause-specific hazards answers “do the cause-specific hazard rates differ?” while Gray’s test answers “do the cumulative incidence functions differ?” These can give different conclusions because the CIF depends on all cause-specific hazards, not just the target one.
The test uses the same IPCW weighting as the Fine-Gray model: subjects with competing events before time t contribute weight G(t-)/G(Ti-), where G is the Kaplan-Meier estimate of the censoring distribution.
Examples
Test whether the cumulative incidence of plasma-cell malignancy (pcm) differs between sexes in the mgus2 dataset:
import greenwood as gw
mg = gw.load_dataset("mgus2", backend="pandas")
etime = mg["ptime"].where(mg["pstat"] == 1, mg["futime"])
cause = mg["pstat"].where(mg["pstat"] == 1, 2 * mg["death"])
cr = gw.Surv.multistate(etime, event=cause, states=("pcm", "death"))
gw.grays_test(cr, group=mg["sex"], cause="pcm")
TestResult(method="Gray's test (cause='pcm')", statistic=1.1945, df=1, p_value=0.2744)
Test the other cause (death) across groups:
gw.grays_test(cr, group=mg["sex"], cause="death")
TestResult(method="Gray's test (cause='death')", statistic=11.6513, df=1, p_value=0.0006416)