跳转至

16.4   生存分析

图书馆想知道会员通常能坚持借阅多久。小率翻到研究截止日,发现有些会员已经停止借阅,有些人仍在活跃。均哥说:“这些还没流失的人不能丢掉,也不能当作已经流失。它们叫删失。”

生存分析(Survival Analysis)研究“事件何时发生”。事件可以是患者复发、机器故障、用户流失,也可以是会员停止借阅。

均哥和小率在图书馆理解生存分析

16.4.1   删失让普通平均值不够用

每个观察对象有两个核心量:

  • 时间 \(T\):从起点到事件或观察结束的时间。
  • 状态 \(\delta\):事件是否已经发生,发生为 1,删失为 0。
会员 观察时间(月) 是否流失
A 8 1
B 12 0
C 5 1
D 15 0

如果把删失的 12 和 15 当作真实流失时间,会低估留存;如果直接删除,又会浪费信息。

生存分析删失与风险集讲解图

16.4.2   生存函数描述仍然活跃的概率

生存函数(Survival Function)定义为:

\[ S(t)=P(T>t) \]

Kaplan-Meier 估计把每个发生事件的时间点串起来:

\[ \hat{S}(t)=\prod_{t_i\le t}\left(1-\frac{d_i}{n_i}\right) \]

其中 \(d_i\) 是时间 \(t_i\) 的事件数,\(n_i\) 是那一刻仍在风险集中的人数。

16.4.3   风险函数看的是下一瞬间的危险

生存函数问“到 \(t\) 时还没有发生事件的概率”。风险函数(Hazard Function)问的是:

已经活到 \(t\) 的对象,在接下来很短时间内发生事件的倾向有多大?

可以写成:

\[ h(t)=\lim_{\Delta t\to 0} \frac{P(t\le T<t+\Delta t\mid T\ge t)}{\Delta t} \]

在用户留存里,风险高意味着“已经留到现在的用户,下一段时间更容易流失”。这比只看平均留存天数更细。

16.4.4   Cox 模型比较不同人群的风险

Cox 比例风险模型(Cox Proportional Hazards Model)常写作:

\[ h(t\mid \mathbf{x})=h_0(t)\exp(\beta_1x_1+\cdots+\beta_px_p) \]

如果某个变量的风险比(Hazard Ratio, HR)为 1.5,意思是:在比例风险假设下,该变量增加对应的风险约为原来的 1.5 倍。HR 小于 1 则表示风险降低。

比例风险假设要检查

Cox 模型假设两组风险比随时间大致恒定。如果早期差异大、后期差异小,或者风险曲线交叉,就要考虑分层、时间交互或其他生存模型。

16.4.5   用 Python 画一条留存曲线

import numpy as np
import matplotlib.pyplot as plt

time = np.array([3, 5, 6, 8, 10, 12])
event = np.array([1, 1, 0, 1, 0, 1])

survival = []
s = 1.0
for t in sorted(set(time[event == 1])):
    at_risk = np.sum(time >= t)
    events = np.sum((time == t) & (event == 1))
    s *= 1 - events / at_risk
    survival.append((t, s))

xs, ys = zip(*survival)
plt.step([0, *xs], [1, *ys], where="post")
plt.ylim(0, 1.05)
plt.xlabel("months")
plt.ylabel("S(t)")
plt.show()

小率的笔记本

生存分析不只关心“是否发生”,更关心“什么时候发生”。删失不是缺失值,而是仍有用的不完整观察。Kaplan-Meier 曲线是理解留存和风险的第一张图。