本記事にはプロモーション(広告・アフィリエイトリンク)が含まれます。

この記事でわかること

💡 ポイント

  • なぜ生存時間データに平均値が使えないのかを、打ち切り割合を変えながらRで実測して示します。打ち切りが27.6%から68.4%へ増えると単純平均は305.2日から170.6日まで崩れる一方、カプランマイヤー法の中央生存期間は310日のまま動きません
  • カプランマイヤー推定量の導出を条件付き確率の積に分解する形で追い、10例の小さなデータで手計算とRの出力が一致することを確認します
  • survfit()の出力の読み方:n.risk・n.event・survival・std.err・95%CIが何を指し、どの数字を報告書に書くのか
  • 中央生存期間(MST)とその95%信頼区間の求め方、そして「中央生存期間が推定できない(NA)」が何を意味するのか
  • 信頼区間の型(log-log / log / plain)で結果が変わること、規制当局向けにどれを選ぶべきか
  • 実務での落とし穴:イベント指標の取り違えで中央生存期間が310日から588日にずれる例、曲線の裾が信用できない理由、Number at riskの必須性

はじめに

新薬の臨床試験で「この薬は effective だったか」を判断するとき、腫瘍領域をはじめとする多くの試験では、血圧や検査値のような連続量ではなくイベントが起きるまでの時間を主要評価項目に据えます。全生存期間(OS)、無増悪生存期間(PFS)、治療失敗までの時間(TTF)などがそれにあたります。

ところがこの「時間」は、普通の連続量として扱うことができません。試験には必ず終わりがあり、データベースロックの時点でまだ生存している被験者が存在します。追跡不能になる方も、他の理由で試験を中止する方もいます。こうした被験者について私たちが知っているのは「少なくともこの時点まではイベントが起きていない」ということだけで、本当の生存時間は分かりません。これが打ち切り(censoring)です。

打ち切りを含むデータをそのまま平均すると、答えは必ず歪みます。かといって打ち切りの被験者を解析から外せば、もっと大きく歪みます。この問題に対する標準解が、1958年に Kaplan と Meier が提案したカプランマイヤー法(Kaplan-Meier法、積の極限法)です。

本記事では、カプランマイヤー法を「なぜ必要なのか」から出発して、推定量の導出、10例のデータでの手計算、Rによる実装と出力の読み方、中央生存期間と信頼区間、そして実務で踏みやすい落とし穴までを整理します。記載しているRの出力はすべて手元のR 4.5.1(survival 3.8.3)で実際に実行した結果です。入口となる生存関数・ハザード関数の定義は生存時間解析の導入と基礎概念〜生存時間とハザード関数を中心に〜で扱っていますので、あわせてご覧ください。

なぜ平均では測れないのか ― 打ち切りが推定を壊す仕組み

打ち切りの概念図:5人の被験者の観察期間を横棒で示し、イベント発生と打ち切りを区別して表した図

まず、打ち切りを無視するとどれだけ壊れるかを数字で確認します。ここでは survival パッケージに含まれる lung データ(North Central Cancer Treatment Group の進行肺癌データ、228例)を使います。追跡期間の上限を人為的に短くしていき、打ち切り割合が増えたときに各指標がどう動くかを見ます。

library(survival)
lung2 <- lung
lung2$status01 <- lung2$status - 1   # 0=打ち切り, 1=死亡 に変換

cut_at <- function(cut){
  d <- lung2
  d$status01 <- ifelse(d$time > cut, 0, d$status01)
  d$time     <- pmin(d$time, cut)
  fit <- survfit(Surv(time, status01) ~ 1, data = d)
  tb  <- summary(fit)$table
  c(cut        = cut,
    censor_pct = round(100 * mean(d$status01 == 0), 1),
    naive_mean = round(mean(d$time), 1),
    event_mean = round(mean(d$time[d$status01 == 1]), 1),
    km_median  = unname(tb["median"]))
}
res <- t(sapply(c(1022, 500, 400, 300, 200), cut_at))
print(as.data.frame(res), row.names = FALSE)
  cut censor_pct naive_mean event_mean km_median
 1022       27.6      305.2      283.0       310
  500       39.5      274.5      211.4       310
  400       44.7      253.5      188.9       310
  300       55.7      221.7      150.3        NA
  200       68.4      170.6      111.8        NA
📝 解釈・補足
同じ母集団を見ているにもかかわらず、全観測時間の単純平均(naive_mean)は305.2日から170.6日へ、44%も縮んでいます。イベントが起きた被験者だけの平均(event_mean)はさらにひどく、283.0日から111.8日へと6割以上短くなりました。患者の生存期間が半分になったわけではなく、「長く生きた人ほど打ち切りになりやすい」という構造がそのまま推定値を押し下げているだけです。

一方、カプランマイヤー法による中央生存期間(km_median)は打ち切り割合が44.7%になるまで310日で不変です。KM法が打ち切りを「その時点までは生存していた」という部分情報として正しく使えているためです。打ち切りが55.7%を超えると NA になりますが、これは計算の失敗ではなく「生存曲線が0.5を下回らないので中央値は定義できない」という正しい報告です(後述します)。

⚠️ 注意
打ち切りを含むデータを扱うとき、Excelで observed time の平均を取って群間で比較する、という処理を目にすることがあります。上の結果が示すとおり、これは両群の打ち切り割合が違えばそれだけで差が出てしまう指標です。群間で追跡期間や脱落の入り方が揃っていることはまずないため、この比較には意味がありません。

ただしKM法が正しく働くには打ち切りが独立(無情報打ち切り)である、すなわち打ち切りになるかどうかがその後のイベント起こりやすさと無関係である必要があります。病状が悪化した患者ほど来院しなくなる、といった状況ではこの仮定が崩れ、推定値は楽観的な方向に偏ります。検定で確かめられる性質ではないため、追跡の徹底と感度分析で担保するのが実務です。

経験生存関数とカプランマイヤー推定量の定義

打ち切りがまったくない理想的な状況であれば、時刻 \(t\) 以上生存する確率は素朴に次のように推定できます。

\[\tilde{S}(t)=\frac{生存時間がt以上となる被験者数}{全被験者数}\]

これが経験生存関数です。しかし打ち切りがあると、分子の「生存時間が \(t\) 以上となる被験者数」を数えることができません。打ち切りになった被験者が \(t\) を超えて生存したのかどうか分からないためです。

そこでカプランマイヤー法は、生存確率をイベントが起きた時点ごとの条件付き生存確率の積に分解します。カプランマイヤー推定量は次で与えられます。

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

ここで各記号は次を意味します。

記号意味Rの出力での名称
\(t_i\)i番目のイベント発生時刻(打ち切りだけの時点は含めない)time
\(n_i\)時刻 \(t_i\) の直前でまだ観察下にある人数(リスク集合の大きさ)n.risk
\(d_i\)時刻 \(t_i\) に発生したイベント数n.event
\(u_i\)区間 \([t_i,t_{i+1})\) に発生した打ち切り数n.censor

打ち切りは \(n_i\) を減らす形でのみ推定に効きます。打ち切りになった被験者は、その時点までのすべての条件付き確率にはきちんと寄与し、その後は分母から静かに退場する――この扱いが、打ち切り情報を捨てずに使うカプランマイヤー法の核心です。

以下では、この推定量が条件付き確率の積から導かれることを追っていきます。数式が続きますが、一度でも導出を見ておくと出力の意味が腑に落ちますし、統計検定準1級レベルの出題対策としても有効です。次のような状況を考えます。

カプランマイヤー法の導出における設定図:イベント発生時点t_i、死亡数d_i、打ち切り数u_iの関係を時間軸上に示した図
💡 記号の設定

  • \(t_{i}\):イベント発生時点
  • \(d_{i}\):死亡数
  • \(u_{i}\):打ち切り数

\(t_{1}<t_{2}<\cdots<t_{r}\) の下で、\(t_{s}\le t<t_{s+1}\) を満たす \(t\) におけるカプランマイヤー推定量を求めます。生存関数の定義から出発して、条件付き確率の連鎖に分解します。

\[\begin{aligned}S(t) &= P(T>t) \\ &= P(T>t,\ T>t_{s}) \\ &= P(T>t_{s})P(T>t\mid T>t_{s}) \\ &= P(T>t_{s-1})P(T>t_{s}\mid T>t_{s-1})P(T>t\mid T>t_{s}) \\ &= \vdots \\ &= P(T>t_{1})P(T>t_{2}\mid T>t_{1})\cdots P(T>t\mid T>t_{s})\end{aligned}\]

ここで \(t_{0}=0\) とすれば \(P(T>t_{0})=1\) であり、先頭の項も条件付き確率として書けます。

\[P(T>t_{1})=P(T>t_{1}\mid T>t_{0})=1-P(T\le t_{1}\mid T>t_{0})\]

したがって生存関数全体が、各区間を「生き延びる条件付き確率」の積として表せます。

\[\begin{aligned}S(t) &= \prod_{i=1}^{s}\bigl(1-P(T\le t_{i}\mid T>t_{i-1})\bigr)\cdot\bigl(1-P(T\le t\mid T>t_{s})\bigr)\\ &= \prod_{i=1}^{s}(1-\lambda_{i})\end{aligned}\]

最後の変形では、\(t_{s}\) と \(t\) の間にはイベントが存在しないため \(P(T\le t\mid T>t_{s})=0\) となること、および \(T\) が \(t_{1},\ldots,t_{r}\) の離散値しか取らないことを使っています。ここで \(\lambda_{i}=P(T=t_{i}\mid T>t_{i-1})\) は「時点 \(t_{i}\) の直前まで生き延びた人が、まさにその時点でイベントを起こす条件付き確率」で、離散ハザードと呼ばれます。

この \(\lambda_i\) を、リスク集合に対するイベントの割合で推定します。

\[\hat{\lambda}_{i}=\frac{d_{i}}{n_{i}},\qquad n_{i}=n-(d_{1}+\cdots+d_{i-1})-(u_{0}+\cdots+u_{i-1})\]

以上をまとめると、カプランマイヤー推定量が得られます。

\[\hat{S}(t)=\prod_{i:t_i \le t}\left(1-\frac{d_{i}}{n_{i}}\right)\]

生存関数の標準誤差はGreenwoodの公式で、信頼区間は生存確率が0から1に収まるよう変換を挟んで構成します。結果だけ示すと次のとおりです。

🔑 標準誤差と信頼区間
標準誤差(Greenwoodの公式):

\[SE(\hat{S}(t))\approx\hat{S}(t)\sqrt{\sum_{i:t_i \le t}\frac{d_{i}}{n_{i}(n_{i}-d_{i})}}\]

信頼区間(変換を用いた構成):

\[g^{-1}\bigl(g(\hat{S}(t))\pm 1.96\,SE[g(\hat{S}(t))]\bigr),\qquad g(x)=\log(-\log x)\]

Greenwoodの公式そのものの導出、Nelson-Aalen推定量やFleming-Harrington推定量との関係はカプラン–マイヤー法における標準誤差と信頼区間の導出で詳しく扱っていますので、理論面を深掘りしたい方はそちらをご覧ください。本記事では後ほど、この公式を手で組んだ値がRの出力と小数第6位まで一致することを確認します。

10例のデータで手を動かす ― 積の極限を追いかける

数式だけでは実感が湧きにくいので、10例の小さなデータで実際に計算します。観察期間(月)と転帰は次のとおりです。

被験者観察時間(月)転帰
14イベント
26打ち切り
37イベント
49イベント
512打ち切り
614イベント
715打ち切り
818イベント
920イベント
1024打ち切り

イベントが起きた時点は4、7、9、14、18、20の6つです。打ち切りだけが起きた時点(6、12、15、24)では曲線は下がりません。それらはリスク集合を1人ずつ減らすだけです。この点を意識しながら、時点ごとに \(n_i\)、\(d_i\)、条件付き生存確率、そして累積の \(\hat{S}(t)\) を並べます。

\(t_i\)\(n_i\)\(d_i\)\(1-d_i/n_i\)\(\hat{S}(t_i)\)直前に退場した打ち切り
41010.9000.900
7810.8750.7876か月で1名
9710.8570.675
14510.8000.54012か月で1名
18310.6670.36015か月で1名
20210.5000.180

たとえば \(t=7\) の行では、直前の6か月時点で1名が打ち切りになっているため、リスク集合は10人ではなく8人です。もし打ち切りの1名を「7か月時点でまだ生存」として数えれば分母は9になり、生存率を過大に見積もることになります。逆に打ち切りの1名を解析から丸ごと除外すれば、4か月時点の情報まで失われます。リスク集合から静かに退場させるという扱いが、この2つの誤りの両方を避けています。

同じデータをRで計算して、手計算と一致するかを確認します。

library(survival)
toy <- data.frame(
  time   = c(4, 6, 7, 9, 12, 14, 15, 18, 20, 24),
  status = c(1, 0, 1, 1,  0,  1,  0,  1,  1,  0)
)
fit_toy <- survfit(Surv(time, status) ~ 1, data = toy, conf.type = "log-log")
summary(fit_toy)
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    4     10       1    0.900  0.0949      0.47301        0.985
    7      8       1    0.787  0.1340      0.38088        0.943
    9      7       1    0.675  0.1551      0.29059        0.882
   14      5       1    0.540  0.1731      0.18117        0.801
   18      3       1    0.360  0.1869      0.06294        0.686
   20      2       1    0.180  0.1579      0.00934        0.533
📝 解釈・補足
survival 列は 0.900 / 0.787 / 0.675 / 0.540 / 0.360 / 0.180 で、手計算と完全に一致しています。n.risk も 10 / 8 / 7 / 5 / 3 / 2 と、打ち切りで減っていく様子がそのまま出ています。

出力に打ち切りだけの時点(6・12・15・24)が現れていない点にも注目してください。summary() はイベントのあった時点のみを表示します。打ち切りの位置は summary(fit_toy, censored = TRUE)fit_toy$n.censor で確認できます。

標準誤差は後半ほど大きくなっています(0.0949 → 0.1579)。リスク集合が2人まで減った時点の推定値0.180は95%信頼区間が [0.009, 0.533] と極端に広く、実質的に何も言えていません。曲線の裾は信用しないという実務上の鉄則は、この数字から来ています。

Rによる実装 ― survfit()の出力を読む

小さなデータで仕組みを確認したので、実データに近い規模で実装します。使うのは先ほどの lung データです。

⚠️ 注意:イベント指標のコーディング
lungstatus1=打ち切り / 2=死亡 というコーディングです。Surv() が期待するのは 0=打ち切り / 1=イベント なので、status-1 の変換が必要です。survival は 1/2 のコーディングもそのまま受け付けてくれますが、外部データを 0/1 に落とし込む過程で意味を逆に取り違えると結果は大きく狂います。実際、この lung でイベント指標を反転させると、中央生存期間は310日から588日(約1.9倍)に化けてしまいます。解析前に table() でイベント数を数え、症例数と臨床的な感覚に合っているかを必ず確認してください。

まず、群別(性別)にカプランマイヤー推定を行い、print() でサマリーを見ます。

library(survival)
lung2 <- lung
lung2$status01 <- lung2$status - 1
lung2$sex_f    <- factor(lung2$sex, levels = c(1, 2), labels = c("Male", "Female"))

fit_sex <- survfit(Surv(time, status01) ~ sex_f, data = lung2, conf.type = "log-log")
print(fit_sex)
               n events median 0.95LCL 0.95UCL
sex_f=Male   138    112    270     210     306
sex_f=Female  90     53    426     345     524
📝 解釈・補足
print() が返す症例数(n)・イベント数(events)・中央生存期間とその95%信頼区間は、そのまま臨床試験報告書やCSRの表に載る値です。

男性の中央生存期間は270日 [210, 306]、女性は426日 [345, 524] で、女性のほうが156日長いという結果でした。両者の信頼区間は重なっていませんが、重なりの有無だけで群間差を判断するのは適切ではなく、後述するログランク検定で正式に評価します。

イベント数にも注目してください。男性は138例中112例(81%)に対し、女性は90例中53例(59%)です。生存時間解析の情報量を決めるのは症例数ではなくイベント数であり、女性群の信頼区間が広いのはこのためです。この考え方は生存時間解析のサンプルサイズ設計でも出発点になります。

報告書では「1年生存率」のように特定時点の生存率を求められることがよくあります。summary()times を渡します。

summary(fit_sex, times = c(0, 180, 365, 540, 730))
                sex_f=Male 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0    138       0   1.0000  0.0000       1.0000        1.000
  180     89      49   0.6445  0.0408       0.5584        0.718
  365     35      36   0.3361  0.0434       0.2527        0.421
  540     17      14   0.1897  0.0385       0.1210        0.270
  730      7      10   0.0781  0.0276       0.0352        0.143

                sex_f=Female 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    0     90       0    1.000  0.0000       1.0000        1.000
  180     71      14    0.842  0.0387       0.7484        0.904
  365     30      22    0.526  0.0597       0.4036        0.635
  540     16       8    0.368  0.0630       0.2467        0.489
  730      6       6    0.187  0.0621       0.0847        0.321
📝 解釈・補足
365日(約1年)時点の生存率は男性33.6% [25.3%, 42.1%]、女性52.6% [40.4%, 63.5%]で、そのまま「1年生存率は男性33.6%、女性52.6%であった」と記述できます。

times を指定したときの n.event は「その時点までの累積イベント数」に変わる点に注意してください。時点ごとの新規イベント数ではありません。

730日時点では n.risk が男性7、女性6まで減っています。リスク集合が10人を切った領域の推定値は参考値で、実際に女性の信頼区間は [8.5%, 32.1%] と非常に広くなっています。

曲線を描くには survminer の ggsurvplot() が便利です。Number at riskの表とログランク検定のp値を同時に出力できます。

library(survminer)
ggsurvplot(
  fit_sex,
  data = lung2,
  risk.table = TRUE,
  conf.int = TRUE,
  pval = TRUE,
  censor.shape = 124,
  censor.size = 3,
  xlab = "Time (days)",
  ylab = "Survival probability",
  break.time.by = 180,
  risk.table.height = 0.25,
  ggtheme = theme_minimal()
)

出力されるカプランマイヤー曲線は次のようになります。

カプランマイヤー曲線の例:階段状に下がる生存曲線、打ち切りを示すヒゲ、下部にNumber at riskの表を配置した図
💡 KM曲線の読み方

  • 階段が落ちる:イベント発生。落ち幅は \(d_i/n_i\) に比例するため、リスク集合が小さい後半ほど1件のイベントで大きく落ちます
  • 縦のヒゲ(tick):打ち切り。曲線は下がらず、以降の分母だけが減ります
  • 網掛け:信頼区間。右へ行くほど広がるのが正常な姿です
  • Number at risk:各時点でまだ観察下にある人数。これが無いKM曲線は読めません。曲線の後半がどれだけの人数に支えられているかを示す唯一の手がかりです
カプランマイヤー曲線の読み方:階段の下降がイベント発生、縦のヒゲが打ち切り、網掛けが95%信頼区間であることを示した注釈図

SASで同じ解析を行う場合は PROC LIFETEST を使います。

proc lifetest data=lung plots=survival(atrisk=0 to 730 by 180 cb=hw);
  time time*status01(0);
  strata sex_f / test=logrank;
run;

time ステートメントの括弧内が打ち切りを表す値である点がRとの大きな違いです。SASとRの実装をより詳しく比較したい方は生存時間解析の基礎:カプラン–マイヤー法と SAS・R による実装を徹底解説で両者を並べて扱っていますので、そちらをご覧ください。

中央生存期間・信頼区間・群間比較

KM曲線を描いたあと、実際に報告するのは要約統計量と検定結果です。ここで押さえておくべき論点を整理します。

中央生存期間(MST)とその信頼区間

中央生存期間は「KM曲線が初めて0.5以下になる時刻」として定義されます。その信頼区間は、生存確率の信頼区間を時間軸に射影する Brookmeyer-Crowley 法で求めるのが標準で、Rでは quantile() で取得できます。

quantile(fit_sex, probs = 0.5)
$quantile
              50
sex_f=Male   270
sex_f=Female 426

$lower
              50
sex_f=Male   210
sex_f=Female 345

$upper
              50
sex_f=Male   306
sex_f=Female 524
⚠️ 中央生存期間が NA になるとき
記事の冒頭で、打ち切りを強めると km_medianNA になることを確認しました。これは曲線が0.5を下回る前に追跡が終わっていることを意味します。エラーではなく、「まだ半数が亡くなっていないので中央値は推定できない」という正しい報告です。

この状況で「中央生存期間は未到達(not reached, NR)」と記載するのは適切ですが、代わりに観測時間の平均を報告してはいけません。中央生存期間が推定できない場合は、特定時点の生存率(1年生存率など)や、後述するRMSTでの要約に切り替えるのが実務的な対応です。

信頼区間の型で結果は変わる

survfit() の conf.type は既定で "log" です。他に "log-log""plain""logit" などが選べます。365日時点で比較してみます。

for (ct in c("log-log", "log", "plain")) {
  f <- survfit(Surv(time, status01) ~ 1, data = lung2, conf.type = ct)
  s <- summary(f, times = 365)
  cat(sprintf("%-8s : S=%.4f  SE=%.4f  95%%CI = [%.4f, %.4f]\n",
              ct, s$surv, s$std.err, s$lower, s$upper))
}
log-log  : S=0.4092  SE=0.0358  95%CI = [0.3387, 0.4784]
log      : S=0.4092  SE=0.0358  95%CI = [0.3447, 0.4858]
plain    : S=0.4092  SE=0.0358  95%CI = [0.3390, 0.4795]
📝 解釈・補足
点推定値0.4092と標準誤差0.0358は共通ですが、信頼区間の下限は0.3387〜0.3447、上限は0.4784〜0.4858とばらつきます。ここでは結論を左右しませんが、生存率が0や1に近い領域ではこの違いが顕在化します。

plain(線形近似)は生存率が0や1に近いと区間が0未満や1超に飛び出すことがあります。log-log はその心配がなく被覆確率の性質も良いため、規制当局向けの解析では log-log が事実上の標準です(SASの PROC LIFETEST も既定が log-log)。Rの既定は log なので、SASと数値を突き合わせる際はまずここを疑ってください。解析計画書(SAP)への明記を強くおすすめします。

Greenwoodの公式を手で組んで検算する

出力を鵜呑みにせず、標準誤差を定義どおりに計算して一致を確認しておきます。

fit_all <- survfit(Surv(time, status01) ~ 1, data = lung2, conf.type = "log-log")
sm   <- summary(fit_all)
idx  <- max(which(sm$time <= 365))
gw   <- cumsum(sm$n.event / (sm$n.risk * (sm$n.risk - sm$n.event)))[idx]
S365 <- sm$surv[idx]
cat(sprintf("S(365) = %.6f\n", S365))
cat(sprintf("Greenwood 手計算 SE = %.6f\n", S365 * sqrt(gw)))
cat(sprintf("survival パッケージ SE = %.6f\n", sm$std.err[idx]))
S(365) = 0.409242
Greenwood 手計算 SE = 0.035824
survival パッケージ SE = 0.035824

小数第6位まで一致しました。前掲のGreenwoodの公式がそのまま実装されていることが確認できます。

群間比較はログランク検定で

曲線の差を正式に評価するにはログランク検定を用います。

survdiff(Surv(time, status01) ~ sex_f, data = lung2)
               N Observed Expected (O-E)^2/E (O-E)^2/V
sex_f=Male   138      112     91.6      4.55      10.3
sex_f=Female  90       53     73.4      5.68      10.3

 Chisq= 10.3  on 1 degrees of freedom, p= 0.001 
📝 解釈・補足
男性は期待イベント数91.6に対して観測112、女性は期待73.4に対して観測53でした。カイ二乗統計量10.3(自由度1)、p = 0.001 で、生存曲線に有意な差があると判断できます。

ログランク検定は比例ハザード性が成り立つときに最も検出力が高い検定です。曲線が交差する場合や、効果が遅れて現れる場合には検出力が落ちるため、そうした状況では一般化ウィルコクソン検定やRMSTによる比較を検討します。導出と使い分けはログランク(log-rank)検定を徹底解説一般化ウィルコクソン検定(Generalized Wilcoxon Test)徹底解説で扱っています。

なお、カプランマイヤー法とログランク検定は共変量を調整できません。年齢やベースラインの重症度を調整したい、効果の大きさをハザード比という1つの数字で表したい、という段階になったらCox比例ハザードモデル入門〜数式から実務応用まで〜へ進んでください。ハザード比という指標そのものの解釈に不安がある方はオッズ比・相対リスク・ハザード比の違いが参考になります。

実務での落とし穴とFAQ

🔑 実務でのポイント

  • Number at riskは必須。曲線の後半が何人に支えられているか分からない図は、査読でも規制当局のレビューでも通りません
  • 中央生存期間は95%信頼区間とセットで報告する
  • conf.typeをSAPに明記する。RとSASで既定値が違い、数値が合わない原因になります
  • 曲線の裾は解釈しない。リスク集合が10人を切った領域は点推定値が大きく振れます
  • 打ち切りの理由を集計しておく。行政的打ち切りと追跡不能・有害事象による中止では、独立打ち切りの仮定への信頼度がまったく違います

Q. 打ち切りが多いとKM曲線は信用できないのでしょうか。

打ち切りの「量」より「入り方」が問題です。行政的打ち切り(データカットオフ時点で生存)が多いだけならKM推定は不偏で、冒頭の実測でも44.7%まで中央生存期間は動きませんでした。危険なのは予後の悪い被験者に偏って打ち切りが発生している場合で、これは無情報打ち切りの仮定が崩れます。打ち切り理由別の集計と、最悪ケースを仮定した感度分析で確認してください。

Q. 生存曲線が交差してしまいました。どうすればよいですか。

曲線の交差は比例ハザード性の破綻を示す典型的なサインです。この状態でハザード比を1つだけ報告すると、時期によって向きが逆の効果を平均してしまい解釈が成立しません。診断手順はCox比例ハザード性のチェックとRMSTへの切り替え判断に、代替指標として有力なRMST(制限付き平均生存時間)のRでの実装はsurvRM2による実装記事にまとめています。

Q. 死亡以外のイベントが混ざる場合もKM法でよいですか。

いいえ。「がんによる死亡までの時間」を見たいときの他病死は、打ち切りではなく競合リスクです。競合イベントを単純に打ち切りとして扱うと、KM法は目的のイベント発生率を過大評価します。この場合は累積発生関数(CIF)とFine-Grayモデルを使います(競合リスクとは ― Fine-Grayモデルと累積発生関数をRで実装)。

Q. 生存時間に分布を仮定してはいけないのですか。

カプランマイヤー法は分布を仮定しない点が強みですが、外挿ができないという弱点があります。追跡期間を超えた将来の生存率を推定したい場合(医療経済評価など)はWeibull分布などを仮定するモデルを使います(パラメトリック生存時間解析とは)。

Q. どの集団で解析するのが正しいですか。

主要解析はFAS(またはITT)が原則です。定義と使い分けはITT・FAS・PP・mITTの違いを完全整理、「何を推定したいのか」の枠組みはICH E9(R1) Estimandフレームワークにまとめています。後治療の開始など中間事象の扱いは打ち切りの定義そのものを変えるため、解析前に決めておく必要があります。

📚 この記事をより深く理解するための参考書籍

カプランマイヤー法は入口の手法ですが、出力の細部を正しく読むには一段深い知識が要ります。実務で長く使える3冊を紹介します。

『カプラン・マイヤー法 ― 生存時間解析の基本手法』西川正子(共立出版・統計学One Point 12、2019年)
カプランマイヤー法だけを一冊まるごと扱った、日本語では稀な本です。本記事で触れた信頼区間・信頼帯・中央生存期間とそのパーセンタイル点の信頼区間について、「解析ソフトの出力をどう読むか」という視点で数値例とともに解説されています。統計の予備知識をそれほど要求しない書き方なので、出力の意味を確実に押さえたい方の最初の一冊として最適です。
『生存時間解析 第2版 ― SASによる生物統計』大橋靖雄・浜田知久馬・魚住龍史(東京大学出版会)
製薬業界の生物統計家にとって長く定番であり続けている一冊で、第2版では記述が全面的に見直されています。本記事の後半で触れた PROC LIFETEST の使い方、log-log信頼区間、ログランク検定からCox回帰への接続が、臨床試験の文脈に沿って解説されています。SASを使う職場で腰を据えて生存時間解析に取り組むなら、手元に置いておきたい本です。
『生存時間解析入門 原書第2版』D. W. ホスマー/S. レメショウ/S. メイ 著/五所正彦 監訳(東京大学出版会)
Applied Survival Analysis(Wiley)の日本語版で、世界的に標準教科書として使われています。本記事で導出した積の極限推定量から、Greenwoodの分散、そして回帰モデルへと進む道筋が丁寧に整理されており、「なぜその式になるのか」を追いたい方に向いています。理論と実データ解析の橋渡しが上手な構成で、統計検定準1級以上の学習にも使えます。

関連記事・次のステップ

生存時間解析そのものが初めてという方は、まず生存時間解析の導入と基礎概念〜生存時間とハザード関数を中心に〜で生存関数とハザード関数の関係を押さえ、SASとRの実装を並べて確認したい方は生存時間解析の基礎:カプラン–マイヤー法と SAS・R による実装へ進んでください。

理論を深めたい方は、本記事で結果だけ示した標準誤差と信頼区間の導出、Nelson-Aalen推定量やFleming-Harrington推定量との関係をカプラン–マイヤー法における標準誤差と信頼区間の導出で追えます。

群間比較へ進む方ログランク(log-rank)検定を徹底解説一般化ウィルコクソン検定で使い分けを、結果の伝え方は信頼区間とp値の関係を図解で理解するで確認できます。回帰モデルへ進む方Cox比例ハザードモデル入門を起点に、層別Cox比例ハザードモデル時間依存性共変量を考慮したCox比例ハザードモデルパラメトリック生存時間解析と読み進めるのがおすすめです。

比例ハザードが成り立たない場面では、比例ハザード性のチェックとRMSTへの切り替え判断で診断手順を確認し、RMST解析ガイドsurvRM2によるRMST実装Win Ratio法で代替指標を検討してください。イベント定義に悩む方は競合リスクとFine-Grayモデル競合リスクイベントの理解と解析法が参考になります。

試験設計の段階にいる方生存時間解析のサンプルサイズ設計 ― 必要イベント数・Schoenfeld式臨床試験のフェーズ(第I相〜第IV相)とはを、解析対象集団と推定目標の整理にはITT・FAS・PP・mITTの違いICH E9(R1) Estimandフレームワークをご覧ください。

まとめ

本記事では、カプランマイヤー法を「なぜ必要なのか」から出発して、推定量の導出、手計算による検証、Rでの実装、そして出力の読み方まで通して紹介しました。

出発点は、打ち切りを含むデータに平均が使えないという事実でした。実測では、打ち切り割合が27.6%から68.4%へ増えるだけで単純平均は305.2日から170.6日へ崩れる一方、カプランマイヤー法の中央生存期間は310日で動きませんでした。KM法は打ち切りを「その時点まで生存していた」という部分情報として使い、リスク集合の分母から静かに退場させることで、この歪みを避けています。

推定量そのものは、生存確率を各イベント時点の条件付き生存確率の積に分解したものでした。10例のデータで手計算した0.900 / 0.787 / 0.675 / 0.540 / 0.360 / 0.180 が survfit() の出力と一致し、Greenwoodの公式を手で組んだ標準誤差0.035824もパッケージの値と小数第6位まで一致しました。仕組みが分かっていれば、出力は検算できます。

実務では、出力のどの数字を報告するかが問われます。中央生存期間は必ず95%信頼区間とセットで示し、conf.type は解析計画書に明記してください。Rの既定は log、SASの既定は log-log であり、この違いだけで数値が合わなくなります。そしてNumber at riskのないKM曲線は読めません。リスク集合が10人を切った領域の推定値を根拠に議論しないという判断も、図に人数が示されて初めて可能になります。

カプランマイヤー法は共変量を調整できず、比例ハザード性が崩れる場面や競合リスクがある場面では単独では不十分です。共変量調整と効果量の表現に進みたい方はCox比例ハザードモデル入門を、曲線が交差するなど比例ハザードが疑わしい方は比例ハザード性のチェックとRMSTへの切り替え判断をご覧いただければと思います。まずは手元のデータで survfit() を実行し、n.risk の減り方を追いながら曲線を眺めるところから始めていただければ、出力の見え方が変わってくるはずです。

ABOUT ME
tomokichi
外資系製薬会社で生物統計家として働ている1児のパパ。生物統計家とは何か、どのようなスキルが必要か、何を行っているのかを共有していきたいと思っております!生物統計に関する最新情報を皆様にお届けすべく、日々奮闘中です。趣味は筋トレ、温泉巡り、家族と散歩。