scikit-survival
Build, evaluate, and audit right-censored or competing-risk survival workflows with scikit-survival, including leakage-safe preprocessing, model selection, probability prediction, and censoring-aware metrics.
Works with
---
name: scikit-survival
description: Build, evaluate, and audit right-censored or competing-risk survival workflows with scikit-survival, including leakage-safe preprocessing, model selection, probability prediction, and censoring-aware metrics.
license: MIT
---
# scikit-survival
## Scope
Use this skill for scikit-survival 0.28.0 workflows involving:
- right-censored structured outcomes;
- Cox PH, Coxnet, IPC ridge, survival trees, forests, boosting, and SVMs;
- discrimination, prediction error, calibration-oriented checks, and time-dependent prediction;
- nonparametric cumulative incidence with competing risks;
- scikit-learn pipelines, nested model selection, and reproducible reports.
scikit-survival primarily models right-censored outcomes. Its built-in competing-risk
support is nonparametric cumulative incidence; it does not provide Fine-Gray regression.
Do not present model output as clinical advice, causal evidence, or proof of clinical
utility.
## Current release and installation
Verified 2026-07-23:
- Latest stable: **scikit-survival 0.28.0**, released 2026-07-05.
- Python: **3.11 or later**; PyPI wheels cover CPython 3.11-3.14 on Linux
x86-64, macOS x86-64/ARM64, and Windows x86-64.
- Runtime bounds: NumPy >=2.0.0, pandas >=2.2.0, SciPy >=1.13.0,
scikit-learn >=1.9.0,<1.10, OSQP >=1.0.2, narwhals >=2.0.1.
- 0.28 adds pandas/Polars estimator support through narwhals and removes
`criterion` from `GradientBoostingSurvivalAnalysis`.
Create an isolated environment and install the tested snapshot:
```bash
uv venv --python 3.11
source .venv/bin/activate
uv pip install \
"scikit-survival==0.28.0" \
"scikit-learn==1.9.0" \
"numpy==2.4.6" \
"pandas==3.0.5" \
"scipy==1.17.1" \
"ecos==2.0.14" \
"osqp==1.1.3" \
"joblib==1.5.3" \
"numexpr==2.14.2" \
"narwhals==2.24.0"
```
Binary wheels are preferred. A source build requires a C/C++ compiler; OSQP may
also require CMake. This skill is MIT-licensed; the upstream scikit-survival package
is GPL-3.0-or-later, so review upstream licensing before redistribution.
## Non-negotiable workflow
1. **Define the estimand and event coding.** Decide whether the target is
all-event survival, cause-specific hazard, or cause-specific cumulative incidence.
2. **Validate outcomes.** Standard estimators need a two-field structured array:
boolean event first, observed time second. Competing-risk CIF instead needs a
separate integer event vector: 0=censored, 1..K=causes.
3. **Split before learned preprocessing.** Never fit imputers, encoders, scalers,
feature selectors, or alpha choices on all rows before splitting.
4. **Fit preprocessing inside a pipeline.** Unknown categories and missingness must
be handled using training-fold state only.
5. **Tune without reusing evaluation data.** Use nested CV when reporting
cross-validated tuned performance, or reserve a truly untouched final holdout.
6. **Fit censoring distributions on training data.** IPCW concordance, dynamic AUC,
and Brier metrics receive `survival_train`, never a pooled train+test outcome.
7. **Restrict evaluation times.** Use a strictly increasing grid inside test
follow-up and below the end of training support where the estimated censoring
survival remains positive.
8. **Match predictions to metrics.** Concordance/dynamic AUC consume higher-is-riskier
scores. Brier metrics consume survival probabilities with shape
`(n_test, n_times)`, not risk scores or unevaluated step functions.
9. **Handle competing causes explicitly.** Standard survival probabilities and CIFs
answer different questions. Never estimate event-specific probability with
`1 - Kaplan-Meier` while censoring competing events.
10. **Report limits.** Separate discrimination, calibration, prediction error,
and cumulative incidence. None alone establishes decision or clinical utility.
## Outcome construction
```python
from sksurv.util import Surv
y = Surv.from_arrays(event=event_bool, time=observed_time)
# Equivalent for pandas or Polars:
y = Surv.from_dataframe("event", "time", frame)
```
The first field is boolean (`True`=event, `False`=right-censored); the second is
floating-point time. Field names may vary, but field order and meaning may not.
Use `references/data-handling.md` before loading custom or competing-risk data.
## Leakage-safe pipeline
```python
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sksurv.linear_model import CoxPHSurvivalAnalysis
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, stratify=y["event"], random_state=20260723
)
preprocess = ColumnTransformer(
[
("num", make_pipeline(SimpleImputer(strategy="median"), StandardScaler()), numeric),
(
"cat",
make_pipeline(
SimpleImputer(strategy="most_frequent"),
OneHotEncoder(handle_unknown="ignore", drop="first", sparse_output=False),
),
categorical,
),
],
sparse_threshold=0.0,
)
model = make_pipeline(preprocess, CoxPHSurvivalAnalysis(alpha=0.1, ties="efron"))
model.fit(X_train, y_train)
risk = model.predict(X_test)
```
The split precedes every learned transformation. For repeated or grouped records,
use a group-aware split; for temporal deployment, use a time-respecting split.
## Model choice
- `CoxPHSurvivalAnalysis`: interpretable log-hazard coefficients under proportional
hazards; `alpha` is ridge shrinkage and `ties` is `"breslow"` or `"efron"`.
- `CoxnetSurvivalAnalysis`: LASSO/elastic-net path for high-dimensional data.
`l1_ratio` is in `(0, 1]`; use `fit_baseline_model=True` before requesting
survival or cumulative-hazard functions.
- `IPCRidge`: IPC-weighted ridge AFT model; prediction is on a time/log-time scale,
not a Cox risk score.
- `RandomSurvivalForest` / `ExtraSurvivalTrees`: nonlinear survival and cumulative
hazard predictions; use permutation importance, not impurity importance.
- `GradientBoostingSurvivalAnalysis`: tree boosting with `"coxph"`, `"squared"`,
or `"ipcwls"` loss. `criterion` was removed in 0.28.
- `ComponentwiseGradientBoostingSurvivalAnalysis`: sparse linear componentwise
boosting.
- `FastSurvivalSVM` / `FastKernelSurvivalSVM`: ranking or regression objectives.
Only `rank_ratio=1` directly returns higher-is-riskier scores; SVMs do not yield
survival probabilities for Brier metrics.
Read the model-specific reference before interpreting coefficients or predictions:
`references/cox-models.md`, `references/ensemble-models.md`, or
`references/svm-models.md`.
## Prediction and metric contracts
```python
import numpy as np
from sksurv.metrics import (
brier_score,
concordance_index_ipcw,
cumulative_dynamic_auc,
integrated_brier_score,
)
risk = model.predict(X_test) # (n_test,), higher means higher event risk
uno_c = concordance_index_ipcw(y_train, y_test, risk, tau=times[-1])[0]
auc_t, mean_auc = cumulative_dynamic_auc(y_train, y_test, risk, times)
surv_fns = model.predict_survival_function(X_test)
surv_prob = np.vstack([fn(times) for fn in surv_fns]) # (n_test, n_times)
_, brier_t = brier_score(y_train, y_test, surv_prob, times)
ibs = integrated_brier_score(y_train, y_test, surv_prob, times)
```
- Harrell C and Uno C measure rank discrimination, not calibration.
- Cumulative/dynamic AUC measures discrimination at selected horizons and accepts
1D or time-dependent 2D risk scores; it rejects survival probabilities.
- Brier score is censoring-weighted probability error and reflects both
discrimination and calibration. It is not a standalone calibration curve.
- Calibration requires horizon-specific predicted-versus-observed checks on
independent data. scikit-survival 0.28 has no dedicated calibration-curve API.
See `references/evaluation-metrics.md` for assumptions, primary literature, safe
time-grid construction, and scorer wrappers.
## Pipelines, metadata routing, and tuning
Ordinary `Pipeline.fit(X, y)` needs no metadata-routing setup. Metric wrappers such
as `as_concordance_index_ipcw_scorer` are estimator wrappers, not `scoring=`
callables:
```python
from sklearn.model_selection import GridSearchCV
from sksurv.metrics import as_concordance_index_ipcw_scorer
wrapped = as_concordance_index_ipcw_scorer(model, tau=tau)
search = GridSearchCV(
wrapped,
{"estimator__coxphsurvivalanalysis__alpha": [0.01, 0.1, 1.0]},
cv=inner_splits,
)
```
The wrapper learns the censoring distribution from each fit fold. Prefix wrapped
parameters with `estimator__`. Enable scikit-learn metadata routing only when
passing extra metadata through a meta-estimator. For example, Coxnet's
`set_predict_request(alpha=True)` matters only when routing the `alpha` prediction
argument with `sklearn.set_config(enable_metadata_routing=True)`.
Use an outer CV loop for an unbiased CV performance estimate after inner tuning.
Do not select parameters and report performance from the same folds as if external.
## Competing risks
```python
from sksurv.nonparametric import cumulative_incidence_competing_risks
# status: integer array, 0=censored, 1..K=mutually exclusive causes
time, cif = cumulative_incidence_competing_risks(status, observed_time)
total_cif = cif[0]
cause_1_cif = cif[1]
```
`cif` has shape `(K + 1, n_times)`; row 0 is total risk and rows 1..K are
cause-specific cumulative incidence. Cause-specific Cox models treat other causes
as censored to estimate cause-specific hazards, but one such model's
`1 - survival` is not the cause-specific CIF. See `references/competing-risks.md`.
## Bundled local CLIs
All helpers use deterministic synthetic data when no input is given. They make no
network calls, reject URLs and symlinks, bound files/rows/features, avoid unsafe
pickle loading, and lazily import scientific packages.
```bash
python skills/scikit-survival/scripts/validate_survival_csv.py --help
python skills/scikit-survival/scripts/train_survival_model.py --help
python skills/scikit-survival/scripts/evaluate_survival_metrics.py --help
python skills/scikit-survival/scripts/competing_risk_cif.py --help
python skills/scikit-survival/scripts/model_report.py --help
```
Typical local flow:
```bash
python skills/scikit-survival/scripts/validate_survival_csv.py \
--input data.csv --event-column event --time-column time \
--feature-columns age,group,measurement --structured-output outcome.npy
python skills/scikit-survival/scripts/train_survival_model.py \
--input data.csv --event-column event --time-column time \
--numeric-columns age,measurement --categorical-columns group \
--model coxph --tune --prediction-output predictions.npz \
--output training-summary.json
python skills/scikit-survival/scripts/evaluate_survival_metrics.py \
--input predictions.npz --output metrics-summary.json
python skills/scikit-survival/scripts/model_report.py \
--training-summary training-summary.json \
--metrics-summary metrics-summary.json --output model-report.md
```
Use only de-identified, authorized local data. The bundled tests contain synthetic
records only and no patient data or PHI.
## Security triage
`SECURITY.md` previously claimed this skill bundled package-shadowing files named
`sklearn.py` and `sksurv.py`. The 2026-07-23 inventory confirmed those files did
not exist; the claim was a phantom analyzer finding. This refresh adds only
descriptively named helpers and no shadow modules, environment reads, or network
calls.
Never name a project script after an imported package (including `sklearn.py`,
`sksurv.py`, `numpy.py`, or `pandas.py`), because Python may import the local file
instead of the installed library. Inspect the working directory before executing
examples copied from untrusted sources.
## Reference files
- `references/data-handling.md` — structured arrays, datasets, schema validation,
pandas/Polars preprocessing, and leakage-safe splitting.
- `references/cox-models.md` — Cox PH, Coxnet, IPCRidge, assumptions, and tuning.
- `references/ensemble-models.md` — forests, trees, boosting, predictions, and
permutation importance.
- `references/svm-models.md` — SVM objectives, prediction direction, scaling,
kernels, and limitations.
- `references/evaluation-metrics.md` — metric inputs, censoring assumptions,
time grids, calibration, nested CV, and primary literature.
- `references/competing-risks.md` — integer event coding, CIF API, built-in
datasets, cause-specific hazards, and unsupported Fine-Gray regression.
## Dated sources
Official API and compatibility sources, checked 2026-07-23:
- [PyPI 0.28.0](https://pypi.org/project/scikit-survival/) — released 2026-07-05.
- [GitHub v0.28.0 release](https://github.com/sebp/scikit-survival/releases/tag/v0.28.0)
— published 2026-07-05.
- [0.28 release notes](https://scikit-survival.readthedocs.io/en/stable/release_notes/v0.28.html).
- [Installation guide](https://scikit-survival.readthedocs.io/en/stable/install.html).
- [Stable user guide](https://scikit-survival.readthedocs.io/en/stable/user_guide/index.html).
- [Stable API reference](https://scikit-survival.readthedocs.io/en/stable/api/index.html).More General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

