# MixtureCure


Mixture cure model with logistic incidence and Cox PH latency.


Usage

``` python
MixtureCure(
    *,
    emmax=50,
    eps=1e-07,
)
```


The population survival is decomposed as:

 S\_{\text{pop}}(t \mid x, z) = 1 - \pi(x) + \pi(x)\\S_u(t \mid z) 

where \pi(x) = \text{expit}(\gamma_0 + \gamma' x) is the probability of being susceptible (uncured) and S_u(t \mid z) = S_0(t)^{\exp(\beta' z)} is the latency survival under a Cox proportional hazards model.

Parameters are estimated via the EM algorithm.


## Parameters


`emmax: int = ``50`  
Maximum number of EM iterations (default 50).

`eps: float = ``1e-07`  
Convergence tolerance for the EM algorithm (default 1e-7).


## Examples

Fit a mixture cure model on the e1684 melanoma dataset:


``` python
import greenwood as gw

e1684 = gw.load_dataset("e1684", backend="polars")

# The right-hand side is the latency submodel; `cure=` sets the incidence submodel
cure = gw.MixtureCure().fit("Surv(FAILTIME, FAILCENS) ~ TRT", cure=["TRT"], data=e1684)
cure
```


    MixtureCure (logistic incidence + Cox PH latency)

    Cure probability model:
                    coef  se(coef)       z         p
    (Intercept)    1.296    0.2977   4.353  1.34e-05
    TRT          -0.5747    0.3454  -1.664    0.0961

    Failure time distribution model:
            coef  se(coef)        z      p
    TRT  -0.1318    0.1659  -0.7946  0.427

    n = 284, events = 196, EM iterations = 31


## Methods

| Name | Description |
|----|----|
| [fit()](#fit) | Fit the mixture cure model via EM. |
| [predict_cure_prob()](#predict_cure_prob) | Predict the probability of being susceptible (uncured). |
| [predict_survival()](#predict_survival) | Predict population survival S\_{\text{pop}}(t \mid x, z). |
| [to_frame()](#to_frame) | Return the summary table as a DataFrame. |

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


### fit()


Fit the mixture cure model via EM.


Usage

``` python
fit(
    surv,
    latency=None,
    cure=None,
    *,
    data=None,
    nboot=100,
)
```


#### Parameters


`surv: Surv | Outcome | str`  
A right-censored [Surv](Surv.md#greenwood.Surv) response. An [Outcome](Outcome.md#greenwood.Outcome) or a formula string such as `'Surv(time, status == 2) ~ age + sex'` is also accepted, with its columns read from `data`. The right-hand side sets `latency`.

`latency: Any = None`  
Covariates for the latency (survival) submodel. A dataframe, 2-D array, or formula string evaluated against `data`. A list of column names in `data` also works.

`cure: Any = None`  
Covariates for the incidence (cure) submodel. A dataframe, 2-D array, or formula string evaluated against `data`. 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, `latency`, and `cure`. When [surv](Outcome.md#greenwood.Outcome.surv) is an [Outcome](Outcome.md#greenwood.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.

`nboot: int = ``100`  
Number of bootstrap resamples for standard errors (default 100).


#### Returns


`MixtureCure`  
The fitted estimator.


#### Examples

Fit a mixture cure model on the `e1684` melanoma dataset. The incidence (cure) submodel and the latency (survival) submodel each receive their own covariates:


``` python
import greenwood as gw

e1684 = gw.load_dataset("e1684", backend="polars")

# The formula's right-hand side sets `latency`
cure = gw.MixtureCure().fit(
    "Surv(FAILTIME, FAILCENS) ~ TRT", cure=["TRT"], data=e1684
)
cure
```


    MixtureCure (logistic incidence + Cox PH latency)

    Cure probability model:
                    coef  se(coef)       z         p
    (Intercept)    1.296    0.2977   4.353  1.34e-05
    TRT          -0.5747    0.3454  -1.664    0.0961

    Failure time distribution model:
            coef  se(coef)        z      p
    TRT  -0.1318    0.1659  -0.7946  0.427

    n = 284, events = 196, EM iterations = 31


Inspect the cure-fraction coefficients. A negative intercept in the cure submodel indicates a large estimated cured fraction:


``` python
gw.tidy(cure, format="polars")
```


shape: (3, 6)

| submodel  | term          | coef      | se       | z         | p        |
|-----------|---------------|-----------|----------|-----------|----------|
| str       | str           | f64       | f64      | f64       | f64      |
| "cure"    | "(Intercept)" | 1.295716  | 0.297664 | 4.352952  | 0.000013 |
| "cure"    | "TRT"         | -0.574748 | 0.345428 | -1.66387  | 0.096138 |
| "latency" | "TRT"         | -0.131835 | 0.165913 | -0.794607 | 0.426842 |


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


### predict_cure_prob()


Predict the probability of being susceptible (uncured).


Usage

``` python
predict_cure_prob(
    cure_covariates,
    *,
    data=None,
)
```


#### Parameters


`cure_covariates: Any`  
Covariates for the incidence submodel (same format as `cure` in `fit`).

`data: Any = None`  
DataFrame for formula evaluation.


#### Returns


`numpy.ndarray`  
Array of susceptibility probabilities (1 = certainly uncured).


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


### predict_survival()


Predict population survival S\_{\text{pop}}(t \mid x, z).


Usage

``` python
predict_survival(
    times,
    latency_covariates,
    cure_covariates,
    *,
    data=None,
)
```


#### Parameters


`times: Any`  
Time points at which to evaluate survival.

`latency_covariates: Any`  
Covariates for the latency submodel.

`cure_covariates: Any`  
Covariates for the incidence submodel.

`data: Any = None`  
DataFrame for formula evaluation.


#### Returns


`numpy.ndarray`  
Array of shape `(n_subjects, n_times)` with population survival probabilities.


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


### to_frame()


Return the summary table as a DataFrame.


Usage

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


Two sections (cure and latency) are stacked, distinguished by a `submodel` column.


#### Parameters


`format: str | None = None`  
Output format: `None` (default), `"pandas"`, `"polars"`, or `"pyarrow"`.


#### Returns


`DataFrame`  
Columns: `submodel`, `term`, `coef`, `se`, `z`, `p`.
