# CensoringDistribution


Kaplan-Meier estimate of the censoring distribution, providing IPC weights.


Usage

``` python
CensoringDistribution(surv)
```


The censoring distribution \hat{G}(t) = P(\text{not censored by time } t) is the Kaplan-Meier estimator applied to the censoring process (where censoring is treated as the "event" and true events are treated as censoring). This is the foundation of all IPCW methods.

IPC weights w_i = 1 / \hat{G}(t_i^-) reweight observed subjects to represent the full population, correcting for the information lost to censoring. Subjects who experienced an event at a time when censoring was heavy receive larger weights (they represent more unobserved subjects), while subjects at times with little censoring receive weights near 1.


## Parameters


`surv: Surv`  
A right-censored [Surv](Surv.md#greenwood.Surv) response. The censoring distribution is estimated from the observed censoring pattern.


## Examples

Estimate the censoring distribution for the lung dataset:


``` python
import greenwood as gw

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

# Build the response from the named columns, then fit the censoring distribution
y = gw.Outcome.surv(time="time", event="status").bind(lung)
cens = gw.CensoringDistribution(y)
cens
```


    CensoringDistribution (n=228, censored=63)
      60 unique censoring times, tail G = 0.0000


Retrieve IPC weights for all subjects:


``` python
# IPC weights: larger where censoring is heavier
weights = cens.weights()
weights[:10]
```


    array([1.35885572, 1.59245456, 0.        , 1.09235351, 3.8210638 ,
           0.        , 1.35885572, 1.41273529, 1.10044502, 1.01015385])


## Methods

| Name | Description |
|----|----|
| [survival()](#survival) | Evaluate the censoring survival function \hat{G}(t) at arbitrary times. |
| [survival_left()](#survival_left) | Evaluate \hat{G}(t^-), the left-continuous censoring survival. |
| [to_frame()](#to_frame) | Return the censoring survival curve as a DataFrame. |
| [weights()](#weights) | IPC weights w_i = \delta_i / \hat{G}(t_i^-) for each subject. |

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


### survival()


Evaluate the censoring survival function \hat{G}(t) at arbitrary times.


Usage

``` python
survival(times)
```


Returns the probability of not being censored by each requested time, estimated via the Kaplan-Meier estimator of the censoring distribution.


#### Parameters


`times: Any`  
1-D array-like of query times.


#### Returns


`ndarray`  
\hat{G}(t) at each query time, shape `(len(times),)`.


#### Examples

Evaluate the probability of remaining uncensored at one year and two years:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Outcome.surv(time="time", event="status").bind(lung)

cens = gw.CensoringDistribution(y)
cens.survival([365, 730])
```


    array([0.69728182, 0.49350505])


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


### survival_left()


Evaluate \hat{G}(t^-), the left-continuous censoring survival.


Usage

``` python
survival_left(times)
```


This is the censoring survival just before each time point, used for IPC weight construction. At the first observation time, \hat{G}(t^-) = 1.


#### Parameters


`times: Any`  
1-D array-like of query times.


#### Returns


`ndarray`  
\hat{G}(t^-) at each query time, shape `(len(times),)`.


#### Examples

The left-continuous version evaluates the censoring survival just before each time point, which is what IPC weights use as denominator:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Outcome.surv(time="time", event="status").bind(lung)

cens = gw.CensoringDistribution(y)
cens.survival_left([365, 730])
```


    array([0.69728182, 0.49350505])


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


### to_frame()


Return the censoring survival curve as a DataFrame.


Usage

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


#### Parameters


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


#### Returns


`DataFrame`  
Columns: `time`, `survival`.


#### Examples

Export the full censoring survival curve as a Polars DataFrame:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Outcome.surv(time="time", event="status").bind(lung)

cens = gw.CensoringDistribution(y)
cens.to_frame(format="polars")
```


shape: (60, 2)

| time   | survival |
|--------|----------|
| f64    | f64      |
| 92.0   | 0.995025 |
| 105.0  | 0.989948 |
| 173.0  | 0.984091 |
| 174.0  | 0.978233 |
| 175.0  | 0.972375 |
| …      | …        |
| 821.0  | 0.327134 |
| 840.0  | 0.261707 |
| 965.0  | 0.174471 |
| 1010.0 | 0.087236 |
| 1022.0 | 0.0      |


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


### weights()


IPC weights w_i = \delta_i / \hat{G}(t_i^-) for each subject.


Usage

``` python
weights(
    *,
    tau=None,
)
```


Uncensored subjects receive weight 1 / \hat{G}(t_i^-). Censored subjects receive weight 0 (they are excluded from the reweighted analysis). Subjects with events after `tau` also receive weight 0.


#### Parameters


`tau: float | None = None`  
Truncation time. Subjects with event times after `tau` receive zero weight. Defaults to the maximum observed time.


#### Returns


`ndarray`  
IPC weights, shape `(n,)`.
