--- 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 compatibility: Requires Python 3.11+, uv, and the pinned scikit-survival 0.28.0 stack for executable examples. Bundled CLIs are local and network-free by default. allowed-tools: Read Write Edit Bash metadata: version: "1.1" skill-author: K-Dense Inc. --- # 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).