mcpField
S
scikit-survival-analysis

scikit-survival-analysis

github.com/jaechang-hits数据与数据库38474 次安装6 天前更新
代码仓库

关于 scikit-survival-analysis

scikit-survival 是基于 scikit-learn 的 Python 生存分析库,面向处理右删失时间结局的数据分析人员。它提供多类模型、非参数估计和删失感知评估指标,并采用 scikit-learn 的拟合与预测接口。

主要功能

  1. 01拟合 Cox 比例风险模型
  2. 02训练生存森林、梯度提升和 SVM
  3. 03估计 Kaplan-Meier 生存曲线
  4. 04处理竞争风险
  5. 05使用删失感知指标评估预测

适用场景

  1. 01分析临床试验的事件时间
  2. 02为可靠性数据构建生存模型
  3. 03比较不同生存模型的预测表现
  4. 04处理高维生存数据并筛选特征

安装

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

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill scikit-survival-analysis

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

附带文件references/data_competing_risks.mdreferences/models_evaluation.md

详细介绍

scikit-survival——生存分析

概述

scikit-survival 是一个基于 scikit-learn 构建的 Python 库,用于分析事件发生时间。它使用 Cox 模型、集成方法、生存 SVM 和非参数估计器处理右删失数据(即事件尚未发生的观测)。所有模型都遵循 scikit-learn 的 fit/predict API,并可与 Pipelines、交叉验证和 GridSearchCV 集成。

适用场景

  • 使用右删失数据对事件发生时间进行建模(临床试验、可靠性分析)
  • 拟合 Cox 比例风险模型(标准模型或弹性网惩罚模型)
  • 构建生存集成模型(Random Survival Forest、Gradient Boosting)
  • 在中等规模数据集上训练生存 SVM,进行基于间隔的学习
  • 使用考虑删失的指标(C-index、Brier 分数、AUC)评估生存预测
  • 估计非参数生存曲线(Kaplan-Meier、Nelson-Aalen)
  • 使用累积发生函数分析竞争风险
  • 对高维生存数据进行分析,并自动选择特征(CoxNet L1/L2)
  • 对于更简单的参数模型(Weibull、对数正态 AFT)或统计检验(log-rank),请使用 lifelines
  • 对于深度学习生存模型,请使用 pycox 或 torchlife

先决条件

pip install scikit-survival scikit-learn pandas numpy matplotlib

Python:>= 3.9。依赖项:scikit-learn、numpy、scipy、pandas、joblib、osqp(用于某些 SVM 求解器)。

数据格式:生存结局采用 NumPy 结构化数组,包含 (event, time) 字段。事件为布尔值(True = 事件已发生,False = 已删失)。时间为正浮点数。

前期访谈

编写任何分析代码之前,请先与用户确认以下事项。

decisions:
  - id: D1
    param: timeAndEventColumns
    kind: required
    source: data
    ask: "Which column holds follow-up time, which holds the event indicator, and does the indicator mark the event or censoring?"
    default: null

  - id: D2
    param: eventDefinition
    kind: required
    source: user
    depends_on: [D1]
    ask: "Which event is being modelled, and are competing events treated as censoring?"
    default: null

  - id: D3
    param: covariates
    kind: required
    source: data
    ask: "Which variables enter the model, and are any measured after baseline?"
    default: null

  - id: D4
    param: modelFamily
    kind: required
    source: user
    ask: "A proportional-hazards model whose coefficients are interpretable, or an ensemble that predicts better but does not yield hazard ratios?"
    default: "Cox proportional hazards"

  - id: D5
    param: regularization
    kind: required
    source: user
    depends_on: [D3, D4]
    ask: "With more covariates than events, should coefficients be penalized - and toward selection or toward shrinkage?"
    default: "none"

  - id: D6
    param: validationScheme
    kind: required
    source: user
    ask: "How should performance be estimated - cross-validation, a held-out split, or an external cohort?"
    default: "cross-validation"

  - id: D7
    param: ensembleHyperparameters
    kind: optional_conditional
    source: user
    depends_on: [D4]
    ask: "How many trees, how deep, and at what learning rate?"
    default: "100 estimators, depth 3, learning rate 0.1"
    skip_if: "a proportional-hazards model was chosen"

之所以先询问 D1 和 D2,是因为如果事件指示器反转,拟合出的模型就会变成对“事件未发生”所需时间的建模,而且所有风险比都会反转,却不会给出任何警告。D3 则涉及另一类隐蔽错误:在基线测量之后获取的协变量会把结局信息泄漏到预测变量中,产生看似出色、实际上无法复现的一致性指数。

快速开始

from sksurv.datasets import load_breast_cancer
from sksurv.ensemble import RandomSurvivalForest
from sksurv.metrics import concordance_index_ipcw
from sklearn.model_selection import train_test_split

X, y = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

rsf = RandomSurvivalForest(n_estimators=100, random_state=42)
rsf.fit(X_train, y_train)

risk_scores = rsf.predict(X_test)
c_index = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
print(f"C-index: {c_index:.3f}")  # e.g., 0.68

# Individual survival curves
surv_fns = rsf.predict_survival_function(X_test[:2])
for fn in surv_fns:
    print(f"5-year survival: {fn(365 * 5):.3f}")

核心 API

模块 1:数据准备

创建生存结构化数组并预处理特征。

import numpy as np
import pandas as pd
from sksurv.util import Surv
from sksurv.preprocessing import OneHotEncoder, encode_categorical
from sksurv.datasets import load_gbsg2, load_breast_cancer
from sklearn.preprocessing import StandardScaler

# Create survival outcome from arrays
event = np.array([True, False, True, True, False])
time = np.array([120.0, 365.0, 200.0, 90.0, 400.0])
y = Surv.from_arrays(event=event, time=time)
print(y.dtype)  # [('event', '?'), ('time', '<f8')]

# From DataFrame columns
# y = Surv.from_dataframe("event_col", "time_col", df)

# Load built-in datasets
# Available: load_gbsg2, load_breast_cancer, load_veterans_lung_cancer,
#            load_whas500, load_aids, load_flchain
X, y = load_gbsg2()
print(f"Shape: {X.shape}, Events: {y['event'].sum()}, "
      f"Censoring rate: {1 - y['event'].mean():.1%}")

# Encode categoricals (survival-aware one-hot)
X_encoded = encode_categorical(X)  # auto-detect and encode all categorical cols

# Standardize (critical for Cox and SVM models)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_encoded)
from sksurv.io import loadarff

# Load ARFF format (Weka format)
data = loadarff("survival_data.arff")
X_arff, y_arff = data[0], data[1]  # DataFrame, structured array
模块 2:Cox 比例风险

半参数模型:h(t|x) = h_0(t) * exp(beta^T x)。系数可解释为对数风险比。

from sksurv.linear_model import CoxPHSurvivalAnalysis, CoxnetSurvivalAnalysis, IPCRidge

# Standard Cox PH model
cox = CoxPHSurvivalAnalysis(alpha=0.0, ties="breslow")
cox.fit(X_train, y_train)
print(f"Coefficients: {cox.coef_}")  # log hazard ratios
# Hazard ratio interpretation: exp(coef) = HR for 1-unit increase
risk_scores = cox.predict(X_test)  # Higher = higher risk

# Survival function for individual patients
surv_funcs = cox.predict_survival_function(X_test[:3])
for fn in surv_funcs:
    print(f"5-year survival: {fn(365 * 5):.3f}")
# Penalized Cox (elastic net) -- for high-dimensional data (p > n)
coxnet = CoxnetSurvivalAnalysis(
    l1_ratio=0.9,           # 0=Ridge, 1=Lasso, between=Elastic Net
    alpha_min_ratio=0.01,   # smallest alpha / largest alpha ratio
    n_alphas=100,           # steps in regularization path
)
coxnet.fit(X_train, y_train)

# Feature selection: non-zero coefficients
selected = np.where(coxnet.coef_ != 0)[0]
print(f"Selected {len(selected)} / {X_train.shape[1]} features")

# IPCRidge: accelerated failure time model (predicts log survival time)
ipcridge = IPCRidge(alpha=1.0)
ipcridge.fit(X_train, y_train)
log_survival_time = ipcridge.predict(X_test)
模块 3:集成方法

用于处理复杂非线性关系的非参数树模型。

from sksurv.ensemble import (
    RandomSurvivalForest,
    GradientBoostingSurvivalAnalysis,
    ComponentwiseGradientBoostingSurvivalAnalysis,
    ExtraSurvivalTrees,
)

# Random Survival Forest -- robust, minimal tuning
rsf = RandomSurvivalForest(
    n_estimators=200, min_samples_split=10, min_samples_leaf=15,
    max_features="sqrt", random_state=42, n_jobs=-1,
)
rsf.fit(X_train, y_train)
risk = rsf.predict(X_test)

# Gradient Boosting -- best performance, needs tuning
gbs = GradientBoostingSurvivalAnalysis(
    loss="coxph",           # "coxph" or "ipcwls" (AFT)
    n_estimators=300, learning_rate=0.05, max_depth=3,
    subsample=0.8, dropout_rate=0.1, random_state=42,
)
gbs.fit(X_train, y_train)

# ComponentwiseGB -- linear model with automatic feature selection
cgbs = ComponentwiseGradientBoostingSurvivalAnalysis(
    n_estimators=100, learning_rate=0.1,
)
cgbs.fit(X_train, y_train)
print(f"Non-zero coefficients: {np.sum(cgbs.coef_ != 0)}")

# ExtraSurvivalTrees -- more regularized than RSF, faster training
est = ExtraSurvivalTrees(n_estimators=100, random_state=42)
est.fit(X_train, y_train)

# Survival curves from any ensemble model
surv_funcs = rsf.predict_survival_function(X_test[:1])
chf_funcs = rsf.predict_cumulative_hazard_function(X_test[:1])
模块 4:生存 SVM

用于生存排序的基于间隔的学习。务必对特征进行标准化。

from sksurv.svm import FastSurvivalSVM, FastKernelSurvivalSVM, HingeLossSurvivalSVM

# Linear SVM -- fast, for linear relationships
lsvm = FastSurvivalSVM(alpha=1.0, rank_ratio=1.0, max_iter=100, random_state=42)
lsvm.fit(X_train_scaled, y_train)
risk = lsvm.predict(X_test_scaled)

# Kernel SVM -- for non-linear relationships (rbf, poly, sigmoid)
ksvm = FastKernelSurvivalSVM(
    alpha=1.0, kernel="rbf", gamma="scale",
    max_iter=50, random_state=42,
)
ksvm.fit(X_train_scaled, y_train)

# Hinge loss variant
hsvm = HingeLossSurvivalSVM(alpha=1.0, random_state=42)
hsvm.fit(X_train_scaled, y_train)
# NaiveSurvivalSVM also available but slower (O(n^3))
from sksurv.kernels import ClinicalKernelTransform

# Clinical kernel: combines clinical + molecular features
# Weighs clinical variables separately from high-dimensional molecular data
transform = ClinicalKernelTransform(fit_once=True)
transform.prepare(X_train)  # auto-detect clinical features
X_kern = transform.fit_transform(X_train)
模块 5:非参数估计

无需模型假设即可估计生存曲线和风险曲线。

from sksurv.nonparametric import kaplan_meier_estimator, nelson_aalen_estimator
import matplotlib.pyplot as plt

# Kaplan-Meier survival curve
time_km, surv_prob = kaplan_meier_estimator(y["event"], y["time"])
plt.step(time_km, surv_prob, where="post")
plt.xlabel("Time (days)")
plt.ylabel("Survival probability")
plt.title("Kaplan-Meier Estimate")
plt.savefig("km_curve.png", dpi=150)

# With confidence intervals
time_km, surv_prob, conf_int = kaplan_meier_estimator(
    y["event"], y["time"], conf_type="log-log",
)

# Nelson-Aalen cumulative hazard
time_na, cum_hazard = nelson_aalen_estimator(y["event"], y["time"])

# Stratified KM by group
for group_name, mask in [("Treated", treated_mask), ("Control", control_mask)]:
    t, s = kaplan_meier_estimator(y[mask]["event"], y[mask]["time"])
    plt.step(t, s, where="post", label=group_name)
plt.legend()
模块 6:评估指标

用于区分能力和校准度的考虑删失指标。

from sksurv.metrics import (
    concordance_index_censored,
    concordance_index_ipcw,
    cumulative_dynamic_auc,
    integrated_brier_score,
    brier_score,
    as_concordance_index_ipcw_scorer,
    as_integrated_brier_score_scorer,
)
import numpy as np

risk_scores = model.predict(X_test)

# Harrell's C-index (simple, biased with high censoring)
c_harrell = concordance_index_censored(
    y_test["event"], y_test["time"], risk_scores
)[0]

# Uno's C-index (recommended -- robust to censoring)
c_uno = concordance_index_ipcw(y_train, y_test, risk_scores)[0]
print(f"C-index (Harrell): {c_harrell:.3f}, (Uno): {c_uno:.3f}")

# Time-dependent AUC at clinically relevant timepoints
times = np.array([365, 730, 1095])  # 1, 2, 3 years
auc, mean_auc = cumulative_dynamic_auc(y_train, y_test, risk_scores, times)
print(f"AUC at 1/2/3yr: {auc}, Mean: {mean_auc:.3f}")

# Integrated Brier Score (measures discrimination + calibration)
surv_funcs = model.predict_survival_function(X_test)
preds = np.row_stack([fn(times) for fn in surv_funcs])
ibs = integrated_brier_score(y_train, y_test, preds, times)
print(f"IBS: {ibs:.3f}")  # Lower is better; compare vs KM baseline
模块 7:竞争风险

多个互斥的事件类型(例如,癌症死亡与心血管疾病死亡)。

from sksurv.nonparametric import cumulative_incidence_competing_risks
from sksurv.linear_model import CoxPHSurvivalAnalysis
from sksurv.util import Surv
import numpy as np

# Cumulative Incidence Function (CIF) estimation
# y_competing: structured array with integer event codes
# (0=censored, 1=relapse, 2=death_in_remission)
time_pts, cif_relapse, cif_death = cumulative_incidence_competing_risks(y_competing)

import matplotlib.pyplot as plt
plt.step(time_pts, cif_relapse, where="post", label="Relapse")
plt.step(time_pts, cif_death, where="post", label="Death in remission")
plt.xlabel("Time")
plt.ylabel("Cumulative Incidence")
plt.legend()

# Cause-specific hazard models: fit separate Cox per event type
event_types = np.array([0, 1, 2, 1, 0, 2, 1])
times = np.array([10.2, 5.3, 8.1, 3.7, 12.5, 6.8, 4.2])

# Model for relapse (event type 1); treat type 2 as censored
y_relapse = Surv.from_arrays(event=(event_types == 1), time=times)
cox_relapse = CoxPHSurvivalAnalysis()
cox_relapse.fit(X, y_relapse)

# Model for death (event type 2); treat type 1 as censored
y_death = Surv.from_arrays(event=(event_types == 2), time=times)
cox_death = CoxPHSurvivalAnalysis()
cox_death.fit(X, y_death)
print(f"Relapse HR (age): {np.exp(cox_relapse.coef_[0]):.3f}")
print(f"Death HR (age): {np.exp(cox_death.coef_[0]):.3f}")

核心概念

模型选择指南
High-dimensional (p > n)?
├── Yes → CoxnetSurvivalAnalysis (elastic net)
└── No
    ├── Need interpretable coefficients?
    │   ├── Yes → CoxPHSurvivalAnalysis or ComponentwiseGB
    │   └── No
    │       ├── Large data (n > 1000) → GradientBoostingSurvivalAnalysis
    │       ├── Medium data → RandomSurvivalForest or FastKernelSurvivalSVM
    │       └── Small data → RandomSurvivalForest
    └── For max performance → compare multiple models
删失类型

scikit-survival 主要处理右删失(截至研究结束时尚未观察到事件)。左删失和区间删失需要使用其他工具(例如 lifelines)。删失率会影响指标的选择:删失率 >40% 时,Uno 的 C-index 通常优于 Harrell 的 C-index。

一致性指数解读
  • 0.5 = 随机预测(没有区分能力)
  • 0.6-0.7 = 中等区分能力
  • 0.7-0.8 = 良好区分能力(临床模型中的常见水平)
  • 0.8+ = 出色(临床生存数据中很少见)
  • C-index 衡量的是排序能力,而非校准度。务必同时使用 Brier 分数。
评估指标决策表
指标衡量内容最适用场景
Harrell's C-index仅排序快速开发、删失率较低
Uno's C-index排序(针对删失进行调整)发表论文、任意删失率
时间依赖 AUC固定 t 时的区分度特定时间范围内的临床决策
Brier 分数(单个 t)固定 t 时的校准度特定时间点的概率准确性
综合 Brier 分数整体校准度全面的模型评估

常见工作流

工作流 1:标准生存分析流程

目标:端到端分析,包括预处理、模型拟合和评估。

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV, train_test_split
from sksurv.datasets import load_breast_cancer
from sksurv.ensemble import GradientBoostingSurvivalAnalysis
from sksurv.metrics import (
    concordance_index_ipcw, cumulative_dynamic_auc,
    integrated_brier_score, as_concordance_index_ipcw_scorer,
)
import numpy as np

X, y = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Build pipeline
pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("model", GradientBoostingSurvivalAnalysis(random_state=42)),
])

# Hyperparameter search
param_grid = {
    "model__learning_rate": [0.01, 0.05, 0.1],
    "model__n_estimators": [100, 200],
    "model__max_depth": [3, 5],
}
cv = GridSearchCV(pipe, param_grid, cv=5,
                  scoring=as_concordance_index_ipcw_scorer(), n_jobs=-1)
cv.fit(X_train, y_train)
print(f"Best CV C-index: {cv.best_score_:.3f}, Params: {cv.best_params_}")

# Final evaluation on test set
best = cv.best_estimator_
risk = best.predict(X_test)
c_uno = concordance_index_ipcw(y_train, y_test, risk)[0]
times = np.percentile(y_test["time"][y_test["event"]], [25, 50, 75])
auc, mean_auc = cumulative_dynamic_auc(y_train, y_test, risk, times)
print(f"Test C-index: {c_uno:.3f}, Mean AUC: {mean_auc:.3f}")
工作流 2:模型比较

目标:比较多个模型系列并选出最佳模型。

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
from sklearn.preprocessing import StandardScaler
import numpy as np

scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

models = {
    "CoxPH": CoxPHSurvivalAnalysis(),
    "RSF": RandomSurvivalForest(n_estimators=200, random_state=42),
    "GBS": GradientBoostingSurvivalAnalysis(n_estimators=200, random_state=42),
    "LinearSVM": FastSurvivalSVM(alpha=1.0, random_state=42),
}

times = np.percentile(y_test["time"][y_test["event"]], [25, 50, 75])
for name, model in models.items():
    X_tr = X_train_s if name in ("CoxPH", "LinearSVM") else X_train
    X_te = X_test_s if name in ("CoxPH", "LinearSVM") else X_test
    model.fit(X_tr, y_train)
    risk = model.predict(X_te)
    c = concordance_index_ipcw(y_train, y_test, risk)[0]
    print(f"{name:12s}: C-index = {c:.3f}")
工作流 3:高维特征选择
  1. 使用 l1_ratio=0.9(以 Lasso 为主)拟合 CoxnetSurvivalAnalysis
  2. 使用 C-index 评分器,通过 GridSearchCV 搜索 alpha_min_ratio 值
  3. 从最佳模型中提取非零系数
  4. 使用选定的特征重新拟合标准 CoxPH 或 RSF,得到最终模型
  5. 在留出的测试集上使用 Uno's C-index 进行评估

关键参数

参数模块默认值范围作用
alphaCoxPH0.0>= 0正则化(0 = 无)
l1_ratioCoxNet0.50-1L1 与 L2 惩罚(1=Lasso,0=Ridge)
n_estimatorsRSF, GBS10050-1000树或迭代次数
max_depthRSF, GBSNone/31-20树深度(GBS:建议 3-5)
learning_rateGBS0.10.001-0.3每次迭代的步长缩减
subsampleGBS1.00.5-1.0每棵树使用的样本比例
dropout_rateGBS0.00-0.3训练时丢弃先前学习器的比例
max_featuresRSFNone"sqrt","log2",int每次分割使用的特征数
alphaFastSurvivalSVM1.00.01-100SVM 正则化
kernelFastKernelSVM"rbf""linear","rbf","poly","sigmoid"核函数
gammaFastKernelSVM"scale""scale","auto",float核系数

最佳实践

  1. 始终对 Cox 和 SVM 模型的特征进行标准化:系数和间隔取决于尺度。请在 Pipeline 中使用 StandardScaler,以防止数据泄漏。

  2. 优先使用 Uno's C-index,而非 Harrell's C-index:它对删失分布差异更稳健;跨数据集比较模型时必须使用。将 y_train 作为第一个参数传入。

  3. 反模式——使用 RSF 内置的特征重要性:它会偏向连续特征和高基数特征。请改用 sklearn.inspection.permutation_importance()。

  4. 报告多个指标:C-index 只能衡量区分度。还应添加 Brier 分数以衡量校准度,并添加时间依赖 AUC 来评估特定时间点的性能。

  5. 反模式——忽略比例风险假设:Cox 模型假设风险比随时间保持恒定。请使用 Schoenfeld 残差(lifelines 中提供)进行验证,或使用非参数替代方法(RSF、GBS)。

  6. 确保每个特征有足够数量的事件:经验法则是 Cox 模型每个特征至少对应 10 个事件。事件较少时,请使用 CoxNet(l1_ratio=0.9)或集成方法。

  7. 使用 scikit-learn Pipelines:将预处理和模型封装在一起,可防止数据泄漏,并简化交叉验证和部署。

  8. 反模式——将竞争事件视为 KM 中的删失事件:存在竞争风险时,Kaplan-Meier 会高估事件概率。请改用 cumulative_incidence_competing_risks()。

  9. GBS 提前停止:对于 GradientBoosting,设置 n_estimators=1000 和 n_iter_no_change=10,以便在验证性能趋于平稳时自动停止。

常见方法

方法:使用交叉验证进行超参数调优
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sksurv.ensemble import RandomSurvivalForest
from sksurv.metrics import as_concordance_index_ipcw_scorer

pipe = Pipeline([
    ("scaler", StandardScaler()),
    ("model", RandomSurvivalForest(random_state=42)),
])
param_grid = {
    "model__n_estimators": [100, 300, 500],
    "model__min_samples_split": [6, 10, 20],
    "model__max_depth": [None, 10, 20],
}
cv = GridSearchCV(pipe, param_grid, cv=5,
                  scoring=as_concordance_index_ipcw_scorer(), n_jobs=-1)
cv.fit(X, y)
print(f"Best: {cv.best_score_:.3f}, Params: {cv.best_params_}")
方法:置换特征重要性
from sklearn.inspection import permutation_importance
from sksurv.metrics import as_concordance_index_ipcw_scorer

result = permutation_importance(
    rsf, X_test, y_test, n_repeats=15,
    scoring=as_concordance_index_ipcw_scorer(), random_state=42, n_jobs=-1,
)
sorted_idx = result.importances_mean.argsort()[::-1]
for i in sorted_idx[:10]:
    print(f"{X.columns[i]:20s}: {result.importances_mean[i]:.4f} "
          f"+/- {result.importances_std[i]:.4f}")
方法:带置信带的 Kaplan-Meier
from sksurv.nonparametric import kaplan_meier_estimator
import matplotlib.pyplot as plt

time, surv, conf_int = kaplan_meier_estimator(
    y["event"], y["time"], conf_type="log-log",
)
plt.step(time, surv, where="post", label="KM estimate")
plt.fill_between(time, conf_int[0], conf_int[1], alpha=0.25, step="post")
plt.xlabel("Time")
plt.ylabel("Survival probability")
plt.legend()
plt.savefig("km_with_ci.png", dpi=150)

故障排除

问题原因解决方案
ValueError: y must be a structured array结局格式错误使用 Surv.from_arrays(event, time) —— event 必须为布尔值,time 必须为浮点数
concordance_index_ipcw 报错缺少 y_train 参数IPCW 需要训练集来估计删失分布;将 y_train 作为第一个参数传入
Cox 模型无法收敛特征相关或未标准化使用 StandardScaler 进行标准化;改用 CoxnetSurvivalAnalysis
C-index 非常低(< 0.5)符号错误或特征没有预测能力检查事件/时间的编码;检查特征工程
交叉验证中 as_concordance_index_ipcw_scorer 报错各折之间的时间范围不匹配确保所有折在待评估时间点均包含事件
SVM 速度极慢使用核 SVM 的大型数据集对较大的 n 使用 FastSurvivalSVM(线性,O(np));核方法则对数据进行子采样
RSF 特征重要性具有误导性内置的不纯度重要性存在偏差使用 scikit-learn 中的 permutation_importance()
Kaplan-Meier 高估风险将竞争事件视为删失改用 cumulative_incidence_competing_risks()

捆绑资源

references/models_evaluation.md

涵盖内容:Cox 模型系列详解(CoxPH、CoxNet、IPCRidge,含参数指导和结果解读)、集成方法(RSF、GBS、ComponentwiseGB、ExtraSurvivalTrees,含超参数调优、提前停止和损失函数)、SVM 模型(FastSurvivalSVM、FastKernelSurvivalSVM、HingeLossSurvivalSVM、NaiveSurvivalSVM、MinlipSurvivalAnalysis,含核选择)、评估指标(Harrell 与 Uno C-index 的选择、时变 AUC 绘图、Brier 分数与零模型对比、完整评估流程)、模型对比表。

已移至内联内容:所有模型系列的核心用法模式已整合至 Core API 第 2–4 模块和第 6 模块。模型选择决策树已移至“关键概念”。

已省略内容:通过评分字符串进行 CoxNet 交叉验证 alpha 选择(这不是有效的 sklearn 评分器用法——请使用 Core API 中所示的 as_concordance_index_ipcw_scorer())。NaiveSurvivalSVM 的详细用法(速度慢,主要用于基准测试)。MinlipSurvivalAnalysis 的详细用法(仅供研究使用)。原始参考文件中重复出现的“适用场景”说明。

整合了 4 个原始文件:cox-models.md(182 行)、ensemble-models.md(327 行)、svm-models.md(411 行)、evaluation-metrics.md(378 行)。总计:1,298 行。

references/data_competing_risks.md

涵盖内容:完整的数据预处理工作流(Surv 数组、自定义 CSV 加载、ARFF 输入/输出、分类变量编码方法、标准化、缺失数据插补策略、特征选择)、数据验证检查(负时间、删失率、每个特征对应的事件数)、训练集/测试集划分(随机划分以及按事件/时间分层划分)、使用 sklearn 的完整预处理流程、竞争风险分析(CIF 估计、含事件类型的数据格式、分层组间比较、原因特异性风险建模、含模拟数据的完整实用示例)。

已移至内联内容:核心 Surv 数组创建、encode_categorical、StandardScaler 用法已整合至 Core API 第 1 模块。CIF 估计和原因特异性 Cox 模型已移至 Core API 第 7 模块。

已省略内容:带有文档字符串的自定义预处理函数(与工作流 1 中展示的 sklearn Pipeline 模式重复)。时变协变量说明(scikit-survival 不支持此功能——原文中仅以一行说明)。Fine-Gray 亚分布模型(scikit-survival 不提供;注明可使用 lifelines 替代)。

整合了 2 个原始文件:data-handling.md(494 行)、competing-risks.md(397 行)。总计:891 行。

相关技能

  • scikit-learn-machine-learning —— 使用相同的 Pipeline/GridSearchCV API 进行通用机器学习;适用于非生存分析任务
  • statsmodels-statistical-modeling —— 频率学派回归(OLS、GLM);适用于非删失结局
  • pymc-bayesian-modeling —— 可指定先验的贝叶斯生存模型
  • matplotlib-scientific-plotting —— 自定义 Kaplan-Meier 曲线和生存曲线图
  • statistical-analysis —— 检验选择框架和报告指南

参考资料

评论

支持 Markdown