## CoxPH


Cox proportional hazards model.


Usage

``` python
CoxPH(
    *,
    ties="efron",
    conf_level=0.95,
)
```


The Cox proportional hazards model is the most widely used regression method for survival data. It models the hazard (instantaneous risk of an event) as a multiplicative function of covariates: \\h(t \mid x) = h_0(t) \exp(\beta^\top x)\\. The model is semi-parametric: the baseline hazard \\h_0(t)\\ is left unspecified (estimated non-parametrically), while covariate effects are estimated parametrically through the log-hazard-ratio coefficients \\\beta\\.

To use this model, call [fit()](AFT.md#greenwood.AFT.fit) with a right-censored or counting-process [Surv](Surv.md#greenwood.Surv) response and a design matrix of covariates (2-D array or DataFrame). The model automatically handles stratification (via `by=` in fit), tied event times (via configurable tie-handling methods), and can compute predictions, baseline hazards, and diagnostic residuals. Results include coefficient estimates with confidence intervals, hazard ratios, standard errors, and global significance tests.

The implementation uses maximum partial likelihood to estimate coefficients. Variance estimates use the observed information matrix (Hessian). The model assumes proportional hazards: the ratio of hazards between two subjects remains constant over time. This can be checked using the [cox_zph()](CoxPH.md#greenwood.CoxPH.cox_zph) method for formal tests or diagnostic plots.


## Parameters


`ties: str = ``"efron"`  
Tie-handling method: `"efron"` (default, as in R) or `"breslow"`.

`conf_level: float = ``0.95`  
Confidence level for coefficient and hazard-ratio 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_`, `concordance_`, `lr_stat_`, `df_`), accessible as arrays or exported to DataFrames.


## Details

Call `fit(surv, covariates)` with a [Surv](Surv.md#greenwood.Surv) response and a design (a 2-D array or a dataframe of covariates). Rows with missing values are dropped (complete-case, as in R's default `na.omit`). Results are exposed as arrays (`coef_`, `std_error_`, `hazard_ratio_`, …) and as tidy frames via [to_frame()](AFT.md#greenwood.AFT.to_frame) (optionally `format=`) and `greenwood.tidy`.


## Examples

Build a [Surv](Surv.md#greenwood.Surv) response from the bundled `lung` dataset and fit the model on `age` and `sex`. Printing the fitted object reports the coefficient table and global tests in the style of R's `summary.coxph`.


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
cox
```


    CoxPH (Cox proportional hazards model, ties='efron')

            coef  exp(coef)  se(coef)       z         p
    age  0.01705      1.017  0.009223   1.848   0.06459
    sex  -0.5132     0.5986    0.1675  -3.065  0.002178

    n = 228, events = 165
    Likelihood ratio test = 14.12 on 2 df, p = 0.0008574


Hazard ratios (and their confidence limits) come from `tidy` with `exponentiate=True`; pass `format=` to choose the backend (here, Polars):


``` python
gw.tidy(cox, 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.017191 | 0.009223  | 1.848078  | 0.064591 | 0.998969 | 1.035747  |
| "sex" | 0.598566 | 0.167458  | -3.06476  | 0.002178 | 0.431094 | 0.831099  |


## Methods

| Name | Description |
|----|----|
| [baseline_hazard()](#baseline_hazard) | Return the uncentered baseline cumulative hazard and survival as a frame. |
| [concordance()](#concordance) | Harrell's concordance index (C-statistic) of the fitted risk scores. |
| [cox_zph()](#cox_zph) | Test the proportional-hazards assumption (Grambsch-Therneau). |
| [fit()](#fit) | Fit the model to a [Surv](Surv.md#greenwood.Surv) response and a covariate design. |
| [predict()](#predict) | Predict from the fitted model. |
| [residuals()](#residuals) | Return diagnostic residuals from the fitted Cox model. |
| [to_frame()](#to_frame) | Return a tidy coefficient table as a DataFrame (one row per term). |

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


#### baseline_hazard()


Return the uncentered baseline cumulative hazard and survival as a frame.


Usage

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


The baseline hazard represents the hazard rate for a reference subject with all covariates at their mean values. It is useful for understanding the underlying time-to-event distribution estimated by the model, and can be combined with individual covariate values to compute predicted survival probabilities for specific subjects.

In Cox proportional hazards models, the hazard for an individual is modeled as: \\h(t \mid x) = h_0(t) \exp(x^\top \beta)\\, where \\h_0(t)\\ is the baseline hazard. This method returns the estimated cumulative baseline hazard \\H_0(t)\\ at each observed event time, evaluated using the Breslow estimator (non-parametric).


##### Parameters


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

- `None` (default): Auto-detects and tries Polars first, falls back to Pandas, then Pyarrow. Raises an error if no DataFrame library is installed.
- `"pandas"`: returns pandas.DataFrame.
- `"polars"`: returns polars.DataFrame.
- `"pyarrow"`: returns pyarrow.Table.


##### Returns


`pandas.DataFrame, polars.DataFrame, or pyarrow.Table`  
A DataFrame with one row per event time containing:

- `time`: Event times at which the baseline hazard is evaluated.
- `cumhaz`: Cumulative baseline hazard \\H_0(t)\\ at each time.
- `survival`: Baseline survival probability \\S_0(t) = \exp(-H_0(t))\\.
- `strata` (if stratified): Stratum label, one baseline hazard per stratum.


##### Details

The baseline hazard is evaluated only at the event times in the training data. The cumulative hazard is non-decreasing by construction. For stratified models, each stratum has its own baseline hazard while coefficients are shared across strata, allowing different baseline risks for different groups.

The baseline survival \\S_0(t)\\ is computed from the cumulative hazard using the relationship \\S_0(t) = \exp(-H_0(t))\\, consistent with the exponential survival model.


##### Examples

The baseline cumulative hazard (and the implied baseline survival) is reported at every event time. Pass `format=` to choose the backend (here, Polars):


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
cox.baseline_hazard(format="polars")
```


shape: (186, 3)

| time   | cumhaz   | survival |
|--------|----------|----------|
| f64    | f64      | f64      |
| 5.0    | 0.002955 | 0.997049 |
| 11.0   | 0.011906 | 0.988164 |
| 12.0   | 0.014928 | 0.985183 |
| 13.0   | 0.021029 | 0.97919  |
| 15.0   | 0.024108 | 0.97618  |
| …      | …        | …        |
| 840.0  | 1.857679 | 0.156034 |
| 883.0  | 2.013058 | 0.13358  |
| 965.0  | 2.013058 | 0.13358  |
| 1010.0 | 2.013058 | 0.13358  |
| 1022.0 | 2.013058 | 0.13358  |


The returned DataFrame shows the estimated hazard and survival trajectory for the reference population (covariates at their means). For stratified models, a separate baseline is provided for each stratum:


``` python
cox_stratified = gw.CoxPH().fit(y, lung[["age", "ph.ecog"]], strata=lung["sex"])
cox_stratified.baseline_hazard(format="polars")
```


shape: (205, 4)

| time  | cumhaz   | survival | strata |
|-------|----------|----------|--------|
| f64   | f64      | f64      | i64    |
| 11.0  | 0.006805 | 0.993218 | 1      |
| 12.0  | 0.009112 | 0.990929 | 1      |
| 13.0  | 0.01381  | 0.986285 | 1      |
| 15.0  | 0.016196 | 0.983935 | 1      |
| 26.0  | 0.018593 | 0.981579 | 1      |
| …     | …        | …        | …      |
| 735.0 | 0.673303 | 0.510021 | 2      |
| 740.0 | 0.673303 | 0.510021 | 2      |
| 765.0 | 0.800708 | 0.449011 | 2      |
| 821.0 | 0.800708 | 0.449011 | 2      |
| 965.0 | 0.800708 | 0.449011 | 2      |


The baseline hazard can be combined with individual predictions to compute personalized survival curves (see `predict(type="survival")`).

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


#### concordance()


Harrell's concordance index (C-statistic) of the fitted risk scores.


Usage

``` python
concordance()
```


The concordance index measures how well the model's predicted risk scores order subjects by their survival times. It ranges from 0 to 1, where 0.5 indicates predictions are no better than random (coin flip), and 1.0 indicates perfect discrimination (the model always assigns higher risk to subjects who die first).

Pairs of subjects are compared: a subject who experiences an event at time t is considered to have "failed before" another subject still under observation at t (including one censored exactly at t). If the model assigns higher risk to the subject who failed first, the pair is concordant. Ties in predicted risk are treated as half-concordant.

For stratified models, only within-stratum pairs are compared.


##### Returns


`float`  
The concordance index, a value between 0 and 1. Typical interpretation:

- 0.5: Random predictions.
- 0.6-0.7: Acceptable discrimination.
- 0.7-0.8: Excellent discrimination.
- 0.8+: Outstanding discrimination.


##### Details

The concordance index is equivalent to the Area Under the Receiver Operating Characteristic curve (AUC) for binary classification problems. It is computed as the fraction of concordant pairs out of all comparable pairs.

Comparable pairs are those where:

- One subject has an event (event=True) and exits at time t.
- The other subject exits at time \> t, OR exits at time = t with event=False (censored).

Tied event times within the same outcome (both events or both censored at the same time) are excluded from comparison.


##### Examples

Harrell's C is returned as a single number between 0 and 1. A value of 0.5 means the model is not better than random guessing; 1.0 means perfect discrimination:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
cox.concordance()
```


    0.6028530028979714


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


#### cox_zph()


Test the proportional-hazards assumption (Grambsch-Therneau).


Usage

``` python
cox_zph(*, transform="identity")
```


The Cox model assumes that the hazard ratio between any two subjects is constant over time (proportional hazards). If this assumption is violated (for example, if a treatment effect diminishes over time) the Cox estimates may be biased. This test checks for violations by regressing scaled Schoenfeld residuals on time.

Large test statistics or small p-values (typically p \< 0.05) suggest the proportional-hazards assumption is violated for that covariate. When violated, consider stratified analysis (separate baseline hazards per stratum), time-dependent covariates, or time-varying coefficients.


##### Parameters


`transform: str = ``"identity"`  
Transformation to apply to time when computing the test. Options are:

- `"identity"` (default): Use time as-is. Regression on raw time.
- `"log"`: Use log(time). Regression on log-transformed time.

Both are validated against R's `cox.zph()` (though R defaults to Kaplan-Meier transform; `"km"` and `"rank"` are planned).


##### Returns


`ZPHResult`  
An object containing per-term test results (`per_term` dict) and a global test (`global_test` dict) across all covariates. Each includes chi-squared statistic, degrees of freedom, and p-value. Access results via `.to_frame()` or dictionary keys.


##### Details

The test uses scaled Schoenfeld residuals, which under the null hypothesis (proportional hazards) have a known asymptotic distribution. The test statistic is approximately chi-squared with 1 df for each term, and chi-squared with degrees of freedom equal to the number of terms for the global test.

Schoenfeld residuals are weighted by the variance-covariance matrix of the risk set at each event time. The regression accounts for the constraint that Schoenfeld residuals sum to zero.


##### Examples

The test returns a [ZPHResult](ZPHResult.md#greenwood.ZPHResult) summarizing per-term and global p-values:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
zph = cox.cox_zph()
zph
```


    ZPHResult(transform='identity', age: p=0.7065, sex: p=0.0992, GLOBAL p=0.2425)


The full statistics are available as a tidy frame, one row per term plus a `GLOBAL` row; pass `format=` to choose the backend (here, Polars):


``` python
zph.to_frame(format="polars")
```


shape: (3, 4)

| term     | chisq    | df  | p_value  |
|----------|----------|-----|----------|
| str      | f64      | i64 | f64      |
| "age"    | 0.141748 | 1   | 0.70655  |
| "sex"    | 2.718401 | 1   | 0.099197 |
| "GLOBAL" | 2.833391 | 2   | 0.242514 |


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


#### fit()


Fit the model to a [Surv](Surv.md#greenwood.Surv) response and a covariate design.


Usage

``` python
fit(
    surv,
    covariates,
    *,
    data=None,
    strata=None,
    robust=False,
    cluster=None,
    max_iter=30,
    tol=1e-09
)
```


`covariates` is a dataframe or 2-D array, or a right-hand-side formula string (for example `"age + sex + C(ph.ecog)"`) evaluated against `data`. `strata` gives per-stratum baseline hazards with shared coefficients. `robust=True` (or providing `cluster` ids) reports the Lin-Wei sandwich variance; `cluster` sums the score residuals within groups before forming the sandwich.


##### Parameters


`surv: Surv`  
A [Surv](Surv.md#greenwood.Surv) object representing the response (censoring type must be right-censored or counting-process).

`covariates: Any`  
Covariate design, either a 2-D array, dataframe, or formula string.

`data: Any = None`  
DataFrame to evaluate formula strings against (required if `covariates=` is a formula string).

`strata: Any = None`  
Optional stratification variable, giving each stratum its own baseline hazard while sharing coefficients. Can be a 1-D array or series.

`robust: bool = ``False`  
If `True`, report Lin-Wei sandwich variance (robust standard errors). Default is `False`.

`cluster: Any = None`  
Optional cluster labels for grouped robust variance estimation. Sums score residuals within groups before forming the sandwich.

`max_iter: int = ``30`  
Maximum number of iterations for the Newton-Raphson solver. Default is `30`.

`tol: float = ``1e-09`  
Convergence tolerance for the optimization. Default is `1e-9`.


##### Returns


`CoxPH`  
Returns self with fitted attributes including `coef_`, `std_error_`, `hazard_ratio_`, `z_`, `p_value_`, and other model diagnostics.


##### Examples

Passing `strata=` gives each stratum its own baseline hazard while sharing the coefficients. Here we fit `age` and `ph.ecog` stratified by sex:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
gw.CoxPH().fit(y, lung[["age", "ph.ecog"]], strata=lung["sex"]).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.010566 | 0.009241  | 1.143364  | 0.252887 | -0.007547 | 0.028679  |
| "ph.ecog" | 0.462424 | 0.114761  | 4.029453  | 0.000056 | 0.237497  | 0.687352  |


The `covariates` argument also accepts a right-hand-side formula string (for example `"age + sex + C(ph.ecog)"`), and `robust=True` reports the Lin-Wei sandwich variance.

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


#### predict()


Predict from the fitted model.


Usage

``` python
predict(
    newdata=None,
    *,
    type="lp",
    times=None,
    conditional_after=None,
    ci=False,
    format=None
)
```


`type` is one of `"lp"` (centered linear predictor), `"risk"` (`exp(lp)`), or `"survival"`. For `"survival"`, returns a frame of survival probabilities at `times` (defaulting to the event times), one column per row of `newdata`. Survival prediction for stratified models is not yet supported.

`conditional_after` (a scalar or one value per subject) predicts survival conditional on having already survived to that time: the returned value at time \\t\\ is \\P(T \> t \mid T \> c) = S(t) / S(c)\\, and is 1 for \\t \le c\\.

With `ci=True` (survival only), the frame also carries `_lower` and `_upper` columns per subject: a pointwise confidence band from the cumulative-hazard standard error (the log transform used by R's `survfit`), at the model's [conf_level](RMSTResult.md#greenwood.RMSTResult.conf_level).


##### Parameters


`newdata: Any = None`  
Covariate design for prediction. If None, predictions are made on the fitted data. Can be a 2-D array or dataframe.

`type: str = ``"lp"`  
Type of prediction: `"lp"` (centered linear predictor, default), `"risk"` (exp of linear predictor), or `"survival"` (survival probability).

`times: Any = None`  
Time points at which to compute survival probabilities (for `type="survival"`). Defaults to the event times from the fitted model.

`conditional_after: Any = None`  
Optional scalar or per-subject time for conditional survival prediction. Computes \\P(T \> t \mid T \> c)\\ where \\c\\ is the conditional_after time.

`ci: bool = ``False`  
If `True` (survival only), include confidence intervals (`_lower` and `_upper` columns). Default is `False`.

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

- `None` (default): Auto-detects and tries Polars first, falls back to Pandas, then Pyarrow. Raises an error if no DataFrame library is installed.
- `"pandas"`: returns pandas.DataFrame.
- `"polars"`: returns polars.DataFrame.
- `"pyarrow"`: returns pyarrow.Table.


##### Returns


`ndarray or DataFrame`  
For `type="lp"` or `"risk"`, returns a 1-D array with one prediction per row. For `type="survival"`, returns a DataFrame with rows for each time point and columns for each subject (named `subject_1`, `subject_2`, etc.), optionally with `_lower` and `_upper` columns for confidence intervals.


##### Examples

The default `type="lp"` returns the centered linear predictor as a NumPy array, one value per fitted subject:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
cox.predict(type="lp")[:5]
```


    array([0.3995047 , 0.2972327 , 0.09268872, 0.10973405, 0.16087005])


With `type="survival"` and `newdata`, the result is a frame of survival probabilities at the requested `times`, one column per new subject. Pass `format=` to choose the backend (here, Polars):


``` python
cox.predict(
    lung[["age", "sex"]][:3], type="survival", times=[180, 365], format="polars"
)
```


shape: (2, 4)

| time  | subject_1 | subject_2 | subject_3 |
|-------|-----------|-----------|-----------|
| f64   | f64       | f64       | f64       |
| 180.0 | 0.62234   | 0.651705  | 0.705421  |
| 365.0 | 0.268757  | 0.305376  | 0.380304  |


Passing `ci=True` adds pointwise confidence bands, and `conditional_after=` gives survival conditional on having already survived to a landmark time.

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


#### residuals()


Return diagnostic residuals from the fitted Cox model.


Usage

``` python
residuals(type="martingale", *, format=None)
```


Residuals measure the difference between observed events and model predictions, helping diagnose model fit and identify outliers or influential observations. Martingale residuals are individual-level; Schoenfeld residuals are event-level and useful for checking the proportional-hazards assumption. Both types can be visualized against time or other variables to detect systematic deviations.


##### Parameters


`type: str = ``"martingale"`  
Type of residuals to return: `"martingale"` (default) or `"schoenfeld"`.

- `"martingale"`: One residual per observation. Ranges from \\-\infty\\ to 1. Positive values suggest the model underestimated risk; negative values suggest overestimation. Useful for overall fit assessment.
- `"schoenfeld"`: One row per event with one column per covariate. Useful for checking the proportional-hazards assumption: plot against time to look for trends. Scaled Schoenfeld residuals are used in the [cox_zph()](CoxPH.md#greenwood.CoxPH.cox_zph) test.

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

- `None` (default): Auto-detects and tries Polars first, falls back to Pandas, then Pyarrow. Raises an error if no DataFrame library is installed.
- `"pandas"`: returns pandas.DataFrame.
- `"polars"`: returns polars.DataFrame.
- `"pyarrow"`: returns pyarrow.Table.

Returns a numpy array for `type="martingale"`.


##### Returns


`ndarray or DataFrame`  
For `type="martingale"`: a 1-D array with one residual per observation. For `type="schoenfeld"`: a DataFrame with one row per event and one column per covariate, ordered by stratum and then event time.


##### Details

Martingale residuals are computed as: \\M_i = \text{event}\_i - H_0(t_i) \exp(X_i \beta)\\, where \\H_0\\ is the baseline cumulative hazard and \\X_i \beta\\ is the linear predictor.

Schoenfeld residuals are computed at each event time as \\X_i - \bar{X}\\, where \\X_i\\ is the covariate vector of the subject with the event and \\\bar{X}\\ is the weighted mean covariate vector for the risk set.


##### Examples

Martingale residuals are returned as one value per observation to assess overall model fit. Large negative residuals may indicate overpredicted risk:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
cox.residuals("martingale")[:5]
```


    array([ 0.00438999, -0.50576203, -3.12981924,  0.53275397, -2.35065745])


Schoenfeld residuals are useful for checking the proportional-hazards assumption by plotting against time or other variables:


``` python
cox.residuals("schoenfeld", format="polars")
```


shape: (165, 2)

| age        | sex       |
|------------|-----------|
| f64        | f64       |
| 0.935465   | 0.72708   |
| 10.00523   | -0.272303 |
| 17.00523   | -0.272303 |
| 3.00523    | -0.272303 |
| 10.140454  | -0.27579  |
| …          | …         |
| 10.761825  | 0.70275   |
| -11.232731 | 0.796743  |
| -2.908253  | -0.155342 |
| 0.611217   | -0.196097 |
| -4.659092  | -0.171473 |


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


#### to_frame()


Return a tidy coefficient table as a DataFrame (one row per term).


Usage

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


The table contains coefficient estimates, standard errors, test statistics, p-values, and confidence limits. If `exponentiate=True`, returns hazard ratios instead of log-hazards.


##### 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`  
If True, return hazard ratios (exp of coefficients). Default is False.


##### Returns


`pandas.DataFrame, polars.DataFrame, or pyarrow.Table`  
One row per term with columns: term, estimate, std_error, statistic, p_value, conf_low, conf_high.


##### Raises


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


##### Examples

Fit a Cox model and export the coefficient table as a Polars frame:


``` python
import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])
cox.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.017045  | 0.009223  | 1.848078  | 0.064591 | -0.001032 | 0.035123  |
| "sex" | -0.513219 | 0.167458  | -3.06476  | 0.002178 | -0.84143  | -0.185007 |


With `exponentiate=True`, estimates become hazard ratios:


``` python
cox.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" | 1.017191 | 0.009223  | 1.848078  | 0.064591 | 0.998969 | 1.035747  |
| "sex" | 0.598566 | 0.167458  | -3.06476  | 0.002178 | 0.431094 | 0.831099  |
