关于 scikit-survival-analysis
scikit-survival 是基于 scikit-learn 的 Python 生存分析库,面向处理右删失时间结局的数据分析人员。它提供多类模型、非参数估计和删失感知评估指标,并采用 scikit-learn 的拟合与预测接口。
主要功能
- 01拟合 Cox 比例风险模型
- 02训练生存森林、梯度提升和 SVM
- 03估计 Kaplan-Meier 生存曲线
- 04处理竞争风险
- 05使用删失感知指标评估预测
适用场景
- 01分析临床试验的事件时间
- 02为可靠性数据构建生存模型
- 03比较不同生存模型的预测表现
- 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:高维特征选择
- 使用 l1_ratio=0.9(以 Lasso 为主)拟合 CoxnetSurvivalAnalysis
- 使用 C-index 评分器,通过 GridSearchCV 搜索 alpha_min_ratio 值
- 从最佳模型中提取非零系数
- 使用选定的特征重新拟合标准 CoxPH 或 RSF,得到最终模型
- 在留出的测试集上使用 Uno's C-index 进行评估
关键参数
| 参数 | 模块 | 默认值 | 范围 | 作用 |
|---|---|---|---|---|
alpha | CoxPH | 0.0 | >= 0 | 正则化(0 = 无) |
l1_ratio | CoxNet | 0.5 | 0-1 | L1 与 L2 惩罚(1=Lasso,0=Ridge) |
n_estimators | RSF, GBS | 100 | 50-1000 | 树或迭代次数 |
max_depth | RSF, GBS | None/3 | 1-20 | 树深度(GBS:建议 3-5) |
learning_rate | GBS | 0.1 | 0.001-0.3 | 每次迭代的步长缩减 |
subsample | GBS | 1.0 | 0.5-1.0 | 每棵树使用的样本比例 |
dropout_rate | GBS | 0.0 | 0-0.3 | 训练时丢弃先前学习器的比例 |
max_features | RSF | None | "sqrt","log2",int | 每次分割使用的特征数 |
alpha | FastSurvivalSVM | 1.0 | 0.01-100 | SVM 正则化 |
kernel | FastKernelSVM | "rbf" | "linear","rbf","poly","sigmoid" | 核函数 |
gamma | FastKernelSVM | "scale" | "scale","auto",float | 核系数 |
最佳实践
-
始终对 Cox 和 SVM 模型的特征进行标准化:系数和间隔取决于尺度。请在 Pipeline 中使用
StandardScaler,以防止数据泄漏。 -
优先使用 Uno's C-index,而非 Harrell's C-index:它对删失分布差异更稳健;跨数据集比较模型时必须使用。将
y_train作为第一个参数传入。 -
反模式——使用 RSF 内置的特征重要性:它会偏向连续特征和高基数特征。请改用
sklearn.inspection.permutation_importance()。 -
报告多个指标:C-index 只能衡量区分度。还应添加 Brier 分数以衡量校准度,并添加时间依赖 AUC 来评估特定时间点的性能。
-
反模式——忽略比例风险假设:Cox 模型假设风险比随时间保持恒定。请使用 Schoenfeld 残差(lifelines 中提供)进行验证,或使用非参数替代方法(RSF、GBS)。
-
确保每个特征有足够数量的事件:经验法则是 Cox 模型每个特征至少对应 10 个事件。事件较少时,请使用 CoxNet(l1_ratio=0.9)或集成方法。
-
使用 scikit-learn Pipelines:将预处理和模型封装在一起,可防止数据泄漏,并简化交叉验证和部署。
-
反模式——将竞争事件视为 KM 中的删失事件:存在竞争风险时,Kaplan-Meier 会高估事件概率。请改用
cumulative_incidence_competing_risks()。 -
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 —— 检验选择框架和报告指南
参考资料
- scikit-survival 文档 —— 官方 API 参考
- scikit-survival GitHub —— 源代码和示例
- API 参考 —— 完整的类和函数列表
- Polsterl(2020)《scikit-survival:基于 scikit-learn 构建的事件发生时间分析库》—— JMLR 21(212):1-6