You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用plotnine绘制Lifelines KM曲线时CI ribbon显示异常求助

Plotnine绘制KM曲线时CI置信带与生存曲线无法对齐的问题解决

问题描述

使用lifelines自带的plot_survival_function()可以生成CI置信带与生存曲线完美对齐的KM曲线:

from lifelines.datasets import load_dd
data = load_dd()
kmf = KaplanMeierFitter()
kmf.fit(data["duration"], event_observed=data["observed"])
kmf.plot_survival_function()
plt.xlim(0, 20)
plt.show()

但改用plotnine重构代码后,CI置信带与阶梯状的生存曲线无法正确匹配对齐:

km_df = kmf.survival_function_.reset_index()
km_df.columns = ["Time", "Survival"]

ci_df = kmf.confidence_interval_.reset_index()
ci_df.columns = ["Time", "Lower", "Upper"]
km_merged = km_df.merge(ci_df, on="Time")

(
    p9.ggplot(km_merged, p9.aes(x="Time", y="Survival")) +
    p9.geom_step(size=1.2, color="blue") +
    p9.geom_ribbon(p9.aes(ymin="Lower", ymax="Upper"), alpha=0.25, fill="blue")
)

问题原因

Kaplan-Meier生存曲线是**阶梯式(step)**的:在两个事件时间点之间,生存率保持恒定,直到下一个事件发生才跳变。而geom_ribbon默认会用直线直接连接相邻时间点的CI上下界,没有遵循阶梯的逻辑,导致置信带的形状和生存曲线的阶梯结构不匹配。lifelines自带的绘图内部会自动为CI置信带生成阶梯式的点,而plotnine需要手动处理这部分数据。

解决方法

手动构造符合阶梯逻辑的CI置信带数据,让每个时间区间内的CI上下界保持恒定,和生存曲线的阶梯结构一致。具体代码如下:

from lifelines.datasets import load_dd
import plotnine as p9
import pandas as pd

# 1. 拟合KM模型
data = load_dd()
kmf = KaplanMeierFitter()
kmf.fit(data["duration"], event_observed=data["observed"])

# 2. 获取生存曲线和CI的基础数据
survival_df = kmf.survival_function_.reset_index()
survival_df.columns = ["Time", "Survival"]
ci_df = kmf.confidence_interval_.reset_index()
ci_df.columns = ["Time", "Lower", "Upper"]

# 3. 构造阶梯式的完整数据(包含每个时间点的前后状态)
step_times = [0]
step_survival = [1.0]
step_lower = [1.0]
step_upper = [1.0]

prev_surv = 1.0
prev_low = 1.0
prev_high = 1.0

for idx, row in survival_df.iterrows():
    curr_time = row["Time"]
    curr_surv = row["Survival"]
    curr_low = ci_df.loc[idx, "Lower"]
    curr_high = ci_df.loc[idx, "Upper"]
    
    # 添加前一个状态延续到当前时间点的记录
    step_times.append(curr_time)
    step_survival.append(prev_surv)
    step_lower.append(prev_low)
    step_upper.append(prev_high)
    
    # 添加当前时间点的新状态记录
    step_times.append(curr_time)
    step_survival.append(curr_surv)
    step_lower.append(curr_low)
    step_upper.append(curr_high)
    
    prev_surv = curr_surv
    prev_low = curr_low
    prev_high = curr_high

# 转换为DataFrame
km_step_data = pd.DataFrame({
    "Time": step_times,
    "Survival": step_survival,
    "Lower": step_lower,
    "Upper": step_upper
})

# 4. 用plotnine绘制对齐的KM曲线和CI置信带
(
    p9.ggplot(km_step_data, p9.aes(x="Time", y="Survival")) +
    p9.geom_step(size=1.2, color="blue") +
    p9.geom_ribbon(p9.aes(ymin="Lower", ymax="Upper"), alpha=0.25, fill="blue") +
    p9.xlim(0, 20)
)

原理说明

通过为每个事件时间点生成两行记录:一行保留上一个时间区间的生存率和CI值(让状态延续到当前时间点),另一行记录当前时间点更新后的状态。这样geom_ribbon绘制时,会在每个时间区间内填充恒定的CI范围,和geom_step绘制的生存曲线完全对齐,还原lifelines自带绘图的效果。

内容的提问来源于stack exchange,提问作者mjs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 02:53:12