## FineGray


Fine-Gray subdistribution hazard model for a competing-risks endpoint.


Usage

``` python
FineGray(
    cause,
    *,
    conf_level=0.95,
)
```


The Fine-Gray model extends Cox regression to competing-risks settings where multiple event types (e.g., disease progression vs. death) can occur and only the first is observed. Rather than modeling the cause-specific hazard (as in standard Cox), it models the subdistribution hazard: the rate at which subjects experience the target cause as if competing events did not occur. This allows inference directly on the cumulative incidence function, making it ideal for policy-relevant questions like "what is the effect of treatment on my probability of experiencing event A?"

Technically, the Fine-Gray model uses a weighted Cox-like approach: subjects who experience a competing event remain in the risk set but with decreasing inverse-probability-of-censoring weights, reflecting their reduced ability to contribute information about the target cause. Call [fit()](AFT.md#greenwood.AFT.fit) with a multi-state [Surv](Surv.md#greenwood.Surv) response (built with [Surv.multistate()](Surv.md#greenwood.Surv.multistate)) and specify the target cause of interest. Coefficients, hazard ratios, and standard errors are computed via weighted partial likelihood, with robust (clustered) standard errors accounting for the weighting scheme.

The implementation automatically computes event weights and handles censoring. Standard errors use the Lin-Wei robust (sandwich) estimator, validated against R's survival package. Unlike the Aalen-Johansen non-parametric approach, Fine-Gray provides covariate-adjusted estimates and supports prediction of cumulative incidence at specified times.


## Parameters


`cause: Any`  
The target cause-of-interest label from the multi-state [Surv](Surv.md#greenwood.Surv) response.

`conf_level: float = ``0.95`  
Confidence level for coefficient intervals (default 0.95).


## Returns


`Fitted estimator`  
Call [fit()](AFT.md#greenwood.AFT.fit) to produce a fitted estimator with cached results (`coef_`, `hazard_ratio_`, `std_error_`, `z_`, `p_value_`, `conf_low_`, `conf_high_`), accessible as arrays or exported to DataFrames.


## Details

Call `fit(surv, covariates)` with a multi-state [Surv](Surv.md#greenwood.Surv) response (built with [Surv.multistate()](Surv.md#greenwood.Surv.multistate)) and specify the target `cause`. The model uses weighted Cox-like optimization with robust standard errors. Results can be tidy frames via [to_frame()](AFT.md#greenwood.AFT.to_frame) (optionally `format=`).


## Examples

Using the same competing-risks setup as [AalenJohansen](AalenJohansen.md#greenwood.AalenJohansen), model the cumulative incidence of plasma-cell malignancy (`"pcm"`) as a function of age and sex. The `age` and `sex` columns of the `mgus2` frame form the covariate design. Printing the fitted object reports the subdistribution-hazard coefficient table.


``` python
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"))
fg = gw.FineGray("pcm").fit(cr, mg[["age", "sex"]])
fg
```


    FineGray (Fine-Gray subdistribution hazard model, cause='pcm')

             coef  exp(coef)  se(coef)       z         p
    age   -0.0173     0.9828  0.005701  -3.035  0.002408
    sexM  -0.2597     0.7713    0.1856  -1.399    0.1617

    n = 1384, events = 115
    Standard errors: robust (clustered)


Passing `exponentiate=True` to `tidy` reports the subdistribution hazard ratios (with their confidence limits) instead of the log-scale coefficients; pass `format=` to choose the backend (here, Polars):


``` python
gw.tidy(fg, 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"  | 0.982848 | 0.005701  | -3.034706 | 0.002408 | 0.971927 | 0.993892  |
| "sexM" | 0.771282 | 0.185579  | -1.399407 | 0.161691 | 0.536103 | 1.109631  |


## Methods

| Name | Description |
|----|----|
| [fit()](#fit) | Fit the Fine-Gray subdistribution hazard model to competing-risks data. |
| [to_frame()](#to_frame) | Return the Fine-Gray coefficient table as a DataFrame. |

------------------------------------------------------------------------


#### fit()


Fit the Fine-Gray subdistribution hazard model to competing-risks data.


Usage

``` python
fit(surv, covariates, *, max_iter=30, tol=1e-09)
```


Fits a Cox-like regression model to the subdistribution hazard of a target cause in a competing-risks setting. Subjects who experience a competing event remain in the risk set with inverse-probability-of-censoring weights, allowing direct inference on cumulative incidence of the target cause. The model reports coefficients, hazard ratios, and clustered robust (Lin-Wei) standard errors.


##### Parameters


`surv: Surv`  
A multi-state [Surv](Surv.md#greenwood.Surv) response built with [Surv.multistate()](Surv.md#greenwood.Surv.multistate). Must have multiple causes-of-interest. Raises `ValueError` if a single-event response is passed.

`covariates: Any`  
A dataframe (pandas or polars) or 2-D array of covariates to adjust for in the subdistribution hazard. An intercept is added automatically. Must have the same number of rows as `surv`.

`max_iter: int = ``30`  
Maximum number of Newton-Raphson iterations (default 30).

`tol: float = ``1e-09`  
Convergence tolerance for coefficient changes (default 1e-9).


##### Returns


`FineGray`  
The fitted estimator object itself (for method chaining) with cached coefficient arrays (`coef_`, `std_error_`, `hazard_ratio_`, `z_`, `p_value_`), event counts, and model fit statistics.


##### Details

The Fine-Gray model estimates the subdistribution hazard \\h_j(t)\\ using weighted partial likelihood. Weights are the inverse of the Kaplan-Meier estimate of the censoring distribution, computed just before each target event time. Subjects with competing events receive time-decreasing weights reflecting reduced ability to contribute information.

Coefficients are interpreted as log-hazard ratios on the subdistribution hazard scale, not the cause-specific hazard. The model directly targets cumulative incidence (\\F_j\\), making it ideal for policy-relevant questions about the probability of experiencing a specific cause.


##### Examples

Fit a Fine-Gray model on the competing-risks `mgus2` dataset, modeling the cumulative incidence of plasma-cell malignancy (pcm) as a function of age and sex:


``` python
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"))
fg = gw.FineGray("pcm").fit(cr, mg[["age", "sex"]])
fg
```


    FineGray (Fine-Gray subdistribution hazard model, cause='pcm')

             coef  exp(coef)  se(coef)       z         p
    age   -0.0173     0.9828  0.005701  -3.035  0.002408
    sexM  -0.2597     0.7713    0.1856  -1.399    0.1617

    n = 1384, events = 115
    Standard errors: robust (clustered)


Extract hazard ratios with exponentiation for interpretation; pass `format=` to choose the backend (here, Polars):


``` python
gw.tidy(fg, 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"  | 0.982848 | 0.005701  | -3.034706 | 0.002408 | 0.971927 | 0.993892  |
| "sexM" | 0.771282 | 0.185579  | -1.399407 | 0.161691 | 0.536103 | 1.109631  |


------------------------------------------------------------------------


#### to_frame()


Return the Fine-Gray coefficient table as a DataFrame.


Usage

``` python
to_frame(*, format=None, exponentiate=False)
```


Exports one row per term with coefficient estimates, robust standard errors, test statistics, p-values, and confidence limits. Set `exponentiate=True` to return subdistribution hazard ratios and exponentiated confidence limits.


##### Parameters


`format: str | None = None`  
Output format: `None` (default), `"pandas"`, `"polars"`, or `"pyarrow"`. When `None`, a backend is auto-detected (Polars, then Pandas, then PyArrow).

`exponentiate: bool = ``False`  
Whether to return subdistribution hazard ratios instead of log-scale coefficients. Default False.


##### Returns


`pandas.DataFrame, polars.DataFrame, or pyarrow.Table`  
A tidy table with columns `term`, `estimate`, `std_error`, `statistic`, `p_value`, `conf_low`, and `conf_high`.


##### Raises


`ImportError`  
If the requested (or, when auto-detecting, any) DataFrame library is not installed.


##### Examples

Fit a Fine-Gray model on the competing-risks `mgus2` data and export the coefficient table as a Polars frame:


``` python
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"))
fg = gw.FineGray("pcm").fit(cr, mg[["age", "sex"]])
fg.to_frame(format="polars")
```


shape: (2, 7)

| term   | estimate  | std_error | statistic | p_value  | conf_low  | conf_high |
|--------|-----------|-----------|-----------|----------|-----------|-----------|
| str    | f64       | f64       | f64       | f64      | f64       | f64       |
| "age"  | -0.017301 | 0.005701  | -3.034706 | 0.002408 | -0.028474 | -0.006127 |
| "sexM" | -0.259701 | 0.185579  | -1.399407 | 0.161691 | -0.62343  | 0.104028  |


To report subdistribution hazard ratios instead of coefficients:


``` python
fg.to_frame(format="polars", exponentiate=True)
```


shape: (2, 7)

| term   | estimate | std_error | statistic | p_value  | conf_low | conf_high |
|--------|----------|-----------|-----------|----------|----------|-----------|
| str    | f64      | f64       | f64       | f64      | f64      | f64       |
| "age"  | 0.982848 | 0.005701  | -3.034706 | 0.002408 | 0.971927 | 0.993892  |
| "sexM" | 0.771282 | 0.185579  | -1.399407 | 0.161691 | 0.536103 | 1.109631  |
