mcpField
A
alterlab-scikit-survival

alterlab-scikit-survival

github.com/alterlab-ieu数据与数据库7868 次安装5 周前更新
代码仓库

关于 alterlab-scikit-survival

alterlab-scikit-survival 是使用 scikit-survival 进行 Python 生存分析的技能,面向处理右删失时间事件数据的分析者。它涵盖 Cox、集成和支持向量机模型,以及生存模型评估和竞争风险分析。

主要功能

  1. 01拟合 Cox 与正则化模型
  2. 02训练生存集成和支持向量机模型
  3. 03估计 Kaplan-Meier 与 Nelson-Aalen 曲线
  4. 04评估模型并分析竞争风险

适用场景

  1. 01对右删失队列数据建立时间事件模型
  2. 02比较生存模型的区分度和校准表现
  3. 03估计生存曲线或特定事件风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/alterlab-ieu/alterlab-academic-skills --skill alterlab-scikit-survival

安装后在 Claude Code 中输入/alterlab-scikit-survival确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
competing-risks.md
cox-models.md
data-handling.md
ensemble-models.md
evaluation-metrics.md
svm-models.md

详细介绍

scikit-survival:Python 生存分析

概览

scikit-survival 是一个基于 scikit-learn 构建的 Python 生存分析库。它提供了专门的工具,用于事件发生时间分析,并处理删失数据这一独特挑战:部分观测结果仅为部分已知。

生存分析旨在建立协变量与事件发生时间之间的联系,同时考虑删失记录(尤其是研究参与者在观察期内未发生事件时产生的右删失数据)。

何时使用此技能

在以下情况下使用此技能:

  • 执行生存分析或事件发生时间建模
  • 处理右删失数据(这是 scikit-survival 的适用范围;左删失或区间删失数据需要使用其他工具)
  • 拟合 Cox 比例风险模型(标准模型或惩罚模型)
  • 构建集成生存模型(随机生存森林、梯度提升)
  • 训练生存支持向量机
  • 评估生存模型的性能(一致性指数、Brier 分数、时变 AUC)
  • 估计 Kaplan-Meier 或 Nelson-Aalen 曲线
  • 分析竞争风险
  • 预处理生存数据或处理生存数据集中的缺失值
  • 使用 scikit-survival 库进行任何分析
不适用的情况
场景改用
固定随访时长下无删失的二元结局(逻辑回归、优势比)alterlab-statsmodels
不涉及事件发生时间结局的标准回归或分类alterlab-scikit-learn
撰写临床决策支持报告,或包含生存曲线和风险比的生物标志物分层队列文档alterlab-clinical-decision

scikit-survival 面向预测:CoxPHSurvivalAnalysis 会返回系数,但不提供标准误、置信区间或 p 值。如果风险比需要进行推断性报告,请使用 lifelines 的 CoxPHFitter 或 statsmodels 的 PHReg(statsmodels.duration.hazard_regression)。

核心功能

1. 模型类型与选择

scikit-survival 提供多种模型系列,适用于不同场景:

Cox 比例风险模型

适用于:系数易于解释的标准生存分析

  • CoxPHSurvivalAnalysis:基础 Cox 模型
  • CoxnetSurvivalAnalysis:用于高维数据的弹性网络惩罚 Cox 模型
  • IPCRidge:用于加速失效时间模型的岭回归

参见:references/cox-models.md,了解 Cox 模型、正则化和结果解释的详细指南

集成方法

适用于:在复杂非线性关系下获得较高预测性能

  • RandomSurvivalForest:稳健的非参数集成方法
  • GradientBoostingSurvivalAnalysis:基于树的提升方法,追求最高性能
  • ComponentwiseGradientBoostingSurvivalAnalysis:具有特征选择功能的线性提升方法
  • ExtraSurvivalTrees:用于进一步正则化的极端随机树

参见:references/ensemble-models.md,了解集成方法、超参数调优以及各模型适用场景的全面指南

生存支持向量机

适用于:使用基于间隔的学习处理中等规模数据集

  • FastSurvivalSVM:针对速度优化的线性 SVM
  • FastKernelSurvivalSVM:用于非线性关系的核 SVM
  • HingeLossSurvivalSVM:使用合页损失的 SVM
  • ClinicalKernelTransform:专用于临床 + 分子数据的核变换

参见:references/svm-models.md,了解 SVM 的详细指南、核选择和超参数调优

模型选择决策树
Start
├─ High-dimensional data (p > n)?
│  ├─ Yes → CoxnetSurvivalAnalysis (elastic net)
│  └─ No → Continue
│
├─ Need interpretable coefficients?
│  ├─ Yes → CoxPHSurvivalAnalysis or ComponentwiseGradientBoostingSurvivalAnalysis
│  └─ No → Continue
│
├─ Complex non-linear relationships expected?
│  ├─ Yes
│  │  ├─ Large dataset (n > 1000) → GradientBoostingSurvivalAnalysis
│  │  ├─ Medium dataset → RandomSurvivalForest or FastKernelSurvivalSVM
│  │  └─ Small dataset → RandomSurvivalForest
│  └─ No → CoxPHSurvivalAnalysis or FastSurvivalSVM
│
└─ For maximum performance → Try multiple models and compare
2. 数据准备与预处理

建模前,应妥善准备生存数据:

创建生存结局
from sksurv.util import Surv

# From separate arrays
y = Surv.from_arrays(event=event_array, time=time_array)

# From DataFrame
y = Surv.from_dataframe('event', 'time', df)

内置数据集使用各自的字段名称和类别特征。 load_breast_cancer() 返回字段 ('e.tdm', 't.tdm'),load_gbsg2() 返回 ('cens', 'time'),load_whas500() 返回 ('fstat', 'lenfol'),而 load_veterans_lung_cancer() 返回 ('Status', 'Survival_in_days');它们的 X 包含 pandas 类别列,缩放器和大多数估计器都无法处理。重用通过 y['event'] / y['time'] 索引的代码前,需先统一这两者:

from sksurv.preprocessing import encode_categorical

X = encode_categorical(X)                          # one-hot encode categorical columns
event_field, time_field = y.dtype.names
y = Surv.from_arrays(event=y[event_field], time=y[time_field])   # fields 'event', 'time'
必要的预处理步骤
  1. 处理缺失值:对特征进行插补
  2. 编码类别变量:独热编码或标签编码
  3. 标准化特征:对 SVM 和正则化 Cox 模型至关重要
  4. 验证数据质量:检查是否存在负时间,以及每个特征对应的事件数是否充足
  5. 划分训练集和测试集:确保各划分中的删失率相近

参见:references/data-handling.md,了解完整的预处理工作流、数据验证和最佳实践

3. 模型评估

恰当的评估对生存模型至关重要。使用能够考虑删失情况的适当指标:

一致性指数(C-index)

用于排序/区分能力的主要指标:

  • Harrell 的 C-index:适用于低删失率(<40%)
  • Uno 的 C-index:适用于中到高删失率(>40%),鲁棒性更强
from sksurv.metrics import concordance_index_censored, concordance_index_ipcw

# Harrell's C-index
c_harrell = concordance_index_censored(y_test['event'], y_test['time'], risk_scores)[0]

# Uno's C-index (recommended)
c_uno = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
时变 AUC

评估特定时间点的区分能力:

from sksurv.metrics import cumulative_dynamic_auc

times = [365, 730, 1095]  # 1, 2, 3 years
auc, mean_auc = cumulative_dynamic_auc(y_train, y_test, risk_scores, times)
Brier 分数

同时评估区分能力和校准度:

from sksurv.metrics import integrated_brier_score

ibs = integrated_brier_score(y_train, y_test, survival_functions, times)

参见:references/evaluation-metrics.md,了解全面的评估指南、指标选择,以及如何在交叉验证中使用评分器

4. 竞争风险分析

处理存在多种互斥事件类型的情况:

from sksurv.nonparametric import cumulative_incidence_competing_risks

# Pass SEPARATE arrays: integer-coded event status (0=censored, 1, 2, ...)
# and the observed time. Do NOT collapse the status to a boolean.
times, cif = cumulative_incidence_competing_risks(event_status, time)
# cif[0] = total risk (any event); cif[1:] = CIF for each event type k
cif_event1, cif_event2 = cif[1], cif[2]

适用竞争风险的情况:

  • 存在多种互斥事件类型(例如,不同原因导致的死亡)
  • 一种事件的发生会阻止其他事件发生
  • 需要估算特定事件类型的发生概率

参见:references/competing-risks.md,了解详细的竞争风险方法、原因特异性风险模型及结果解读

5. 非参数估计

在不作参数假设的情况下估计生存函数:

Kaplan-Meier 估计量
from sksurv.nonparametric import kaplan_meier_estimator

time, survival_prob = kaplan_meier_estimator(y['event'], y['time'])
Nelson-Aalen 估计量
from sksurv.nonparametric import nelson_aalen_estimator

time, cumulative_hazard = nelson_aalen_estimator(y['event'], y['time'])

典型工作流

工作流 1:标准生存分析
from sksurv.datasets import load_breast_cancer
from sksurv.linear_model import CoxPHSurvivalAnalysis
from sksurv.metrics import concordance_index_ipcw
from sksurv.preprocessing import encode_categorical
from sksurv.util import Surv
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 1. Load and prepare data (encode categoricals; rename outcome fields to event/time)
X, y = load_breast_cancer()
X = encode_categorical(X)
event_field, time_field = y.dtype.names          # ('e.tdm', 't.tdm') for this dataset
y = Surv.from_arrays(event=y[event_field], time=y[time_field])
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y['event'])

# 2. Preprocess
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 3. Fit model (alpha > 0 adds a ridge penalty; unpenalized Cox fails when
#    features are many relative to events, as in this 198-patient, 80-feature dataset)
estimator = CoxPHSurvivalAnalysis(alpha=0.1)
estimator.fit(X_train_scaled, y_train)

# 4. Predict
risk_scores = estimator.predict(X_test_scaled)

# 5. Evaluate
c_index = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
print(f"C-index: {c_index:.3f}")
工作流 2:使用特征选择处理高维数据

IPCW 评分器封装器(as_concordance_index_ipcw_scorer、as_integrated_brier_score_scorer、as_cumulative_dynamic_auc_scorer)会封装估计器并重写其 .score() 方法——它们不会传入 scoring=。请将封装后的对象作为 GridSearchCV 估计器,并为待调优参数添加前缀 estimator__。scoring='concordance_index_ipcw' 不是有效的字符串。

CoxnetSurvivalAnalysis 会拟合整条正则化路径:coef_ 的形状为 (n_features, n_alphas),每列对应 alphas_ 中的一个惩罚值。先从该路径中调优单个惩罚值,再读取所选列中的非零系数。

import numpy as np
from sksurv.linear_model import CoxnetSurvivalAnalysis
from sklearn.model_selection import GridSearchCV
from sksurv.metrics import as_concordance_index_ipcw_scorer

# 1. Fit once to get the penalty path (l1_ratio near 1 = lasso-like sparsity)
path = CoxnetSurvivalAnalysis(l1_ratio=0.9, alpha_min_ratio=0.01).fit(X_train_scaled, y_train)

# 2. Wrap the estimator so .score() uses Uno's C-index, then tune one alpha per fit.
#    tau caps the evaluation horizon to avoid unstable IPCW weights in the tail.
wrapped = as_concordance_index_ipcw_scorer(
    CoxnetSurvivalAnalysis(l1_ratio=0.9, fit_baseline_model=True), tau=y_train['time'].max())
param_grid = {'estimator__alphas': [[a] for a in path.alphas_]}
# With p >> n the smallest penalties can fail to converge; GridSearchCV reports them as
# FitFailedWarning / NaN scores and still selects among the penalties that fit.
cv = GridSearchCV(wrapped, param_grid, cv=5)
cv.fit(X_train_scaled, y_train)

# 3. Identify selected features (unwrap to reach the Coxnet estimator; coef_ is (n_features, 1))
best_model = cv.best_estimator_.estimator_
selected_features = X.columns[np.flatnonzero(best_model.coef_[:, 0])]
工作流 3:实现最高性能的集成方法
from sksurv.ensemble import GradientBoostingSurvivalAnalysis
from sklearn.model_selection import GridSearchCV
from sksurv.metrics import as_concordance_index_ipcw_scorer, concordance_index_ipcw

# 1. Define parameter grid
param_grid = {
    'learning_rate': [0.01, 0.05, 0.1],
    'n_estimators': [100, 200, 300],
    'max_depth': [3, 5, 7]
}

# 2. Grid search (wrap estimator so .score() is Uno's C-index; prefix params)
gbs = GradientBoostingSurvivalAnalysis(random_state=42)
wrapped = as_concordance_index_ipcw_scorer(gbs, tau=y_train['time'].max())
param_grid = {f'estimator__{k}': v for k, v in param_grid.items()}
cv = GridSearchCV(wrapped, param_grid, cv=5, n_jobs=-1)
cv.fit(X_train, y_train)

# 3. Evaluate best model on held-out test set
best_model = cv.best_estimator_.estimator_
risk_scores = best_model.predict(X_test)
c_index = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
工作流 4:全面比较模型
from sksurv.linear_model import CoxPHSurvivalAnalysis
from sksurv.ensemble import RandomSurvivalForest, GradientBoostingSurvivalAnalysis
from sksurv.svm import FastSurvivalSVM
from sksurv.metrics import concordance_index_ipcw, integrated_brier_score

# Define models
models = {
    'Cox': CoxPHSurvivalAnalysis(alpha=0.1),
    'RSF': RandomSurvivalForest(n_estimators=100, random_state=42),
    'GBS': GradientBoostingSurvivalAnalysis(random_state=42),
    'SVM': FastSurvivalSVM(random_state=42)
}

# Evaluate each model
results = {}
for name, model in models.items():
    model.fit(X_train_scaled, y_train)
    risk_scores = model.predict(X_test_scaled)
    c_index = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
    results[name] = c_index
    print(f"{name}: C-index = {c_index:.3f}")

# Select best model
best_model_name = max(results, key=results.get)
print(f"\nBest model: {best_model_name}")

与 scikit-learn 集成

scikit-survival 与 scikit-learn 生态系统全面集成:

from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sksurv.linear_model import CoxPHSurvivalAnalysis
from sksurv.metrics import as_concordance_index_ipcw_scorer

# Build the pipeline, then wrap it so .score() is Uno's C-index.
# Wrapping the whole pipeline keeps scaling inside each CV fold (no leakage).
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', CoxPHSurvivalAnalysis())
])
wrapped = as_concordance_index_ipcw_scorer(pipeline, tau=y['time'].max())

# Cross-validation uses the wrapped estimator's .score(); leave scoring=None
scores = cross_val_score(wrapped, X, y, cv=5)

# Grid search: params live under estimator__ (wrapper) then the pipeline step
param_grid = {'estimator__model__alpha': [0.1, 1.0, 10.0]}
cv = GridSearchCV(wrapped, param_grid, cv=5)
cv.fit(X, y)

最佳实践

  1. 始终对 SVM 和正则化 Cox 模型的特征进行标准化
  2. 当删失率 > 40% 时,使用 Uno's C-index,而非 Harrell's C-index
  3. 报告多种评估指标(C-index、积分 Brier 分数、时间依赖 AUC)
  4. 检查 Cox 模型的比例风险假设
  5. 使用交叉验证,并选择合适的评分器来调优超参数
  6. 建模前验证数据质量(检查负时间值、每个特征对应的事件数量是否充足)
  7. 比较多种模型类型,以找到性能最佳的模型
  8. 对随机生存森林使用置换重要性(而非内置重要性)
  9. 存在多种事件类型时,考虑竞争风险
  10. 在分析中记录删失机制和删失率

应避免的常见陷阱

  1. 删失率高时使用 Harrell's C-index → 使用 Uno's C-index
  2. 未对 SVM 特征进行标准化 → 始终进行标准化
  3. 忘记向 concordance_index_ipcw 传入 y_train → 计算 IPCW 时必需
  4. 将竞争事件视为删失 → 使用竞争风险方法
  5. 未检查每个特征对应的事件数量是否充足 → 经验法则:每个特征至少对应 10 个事件
  6. 使用 RSF 的内置特征重要性 → 使用置换重要性
  7. 忽略比例风险假设 → 验证该假设,或使用替代模型
  8. 将 as_concordance_index_ipcw_scorer() 传给 scoring= → 它会包装估计器(覆盖 .score());应将包装后的对象作为估计器传入,并为参数添加 estimator__ 前缀

版本说明

  • scikit-survival 0.28(2026 年 7 月)要求 scikit-learn ≥ 1.9,所有估计器均接受 polars DataFrame,并从 GradientBoostingSurvivalAnalysis 中移除了 criterion 参数;0.27 增加了对 pandas 3 的支持。
  • CoxnetSurvivalAnalysis 要求 0 < l1_ratio ≤ 1;若要使用纯岭惩罚项,请使用 CoxPHSurvivalAnalysis(alpha=...)。

参考文件

此技能包含针对特定主题的详细参考文件:

  • references/cox-models.md:Cox 比例风险模型、惩罚 Cox(CoxNet)、IPCRidge、正则化策略和结果解读的完整指南
  • references/ensemble-models.md:随机生存森林、梯度提升、超参数调优、特征重要性和模型选择
  • references/evaluation-metrics.md:一致性指数(Harrell's 与 Uno's)、时间依赖 AUC、Brier 分数和完整评估流程
  • references/data-handling.md:数据加载、预处理工作流、缺失数据处理、特征编码和验证检查
  • references/svm-models.md:生存支持向量机、核选择、临床核变换和超参数调优
  • references/competing-risks.md:竞争风险分析、累积发生函数和原因特异性风险模型

需要针对特定任务获取详细信息时,请加载这些参考文件。

其他资源

快速参考:关键导入

# Models
from sksurv.linear_model import CoxPHSurvivalAnalysis, CoxnetSurvivalAnalysis, IPCRidge
from sksurv.ensemble import RandomSurvivalForest, GradientBoostingSurvivalAnalysis
from sksurv.svm import FastSurvivalSVM, FastKernelSurvivalSVM
from sksurv.tree import SurvivalTree

# Evaluation metrics
from sksurv.metrics import (
    concordance_index_censored,
    concordance_index_ipcw,
    cumulative_dynamic_auc,
    brier_score,
    integrated_brier_score,
    as_concordance_index_ipcw_scorer,
    as_integrated_brier_score_scorer
)

# Non-parametric estimation
from sksurv.nonparametric import (
    kaplan_meier_estimator,
    nelson_aalen_estimator,
    cumulative_incidence_competing_risks
)

# Data handling
from sksurv.util import Surv
from sksurv.preprocessing import OneHotEncoder, encode_categorical
from sksurv.datasets import load_gbsg2, load_breast_cancer, load_veterans_lung_cancer

# Kernels
from sksurv.kernels import ClinicalKernelTransform

评论

支持 Markdown