「先生!がん患者さんの5年がん特異死亡率を調べたくて、追跡途中で他病死(老衰や心不全など)された患者さんを『中途打切り(Censoring)』として1-KM(1 – Kaplan-Meier)曲線を描きました!綺麗に死亡率が上昇していくグラフが描けました!」
……ちょっと待ってほしい。それは臨床研究の論文査読(Peer Review)において、統計査読者から「競合リスクを考慮しておらず、イベント率が著しく過大評価(Overestimate)されている」と一発で却下される代表的な罠である。
がん特異死亡や特定の心血管イベントなど、「目的とするイベントが起こる前に、別のイベント(他病死など)が発生して目的イベントが絶対に起こらなくなる状況」 を統計学では 競合リスク(Competing Risks) と呼ぶ。
競合イベントを起こした人を単なる「追跡不能」と同じ「打切り」として処理してしまうと、分母(リスク集合)が不当に小さくなり、目的イベントの発生率が実際よりも大幅に高く見積もられてしまう。
本記事では、なぜ1-KM曲線がイベント率を過大評価してしまうのかというメカニズムから、競合リスク下の正攻法である 累積発生関数(CIF: Cumulative Incidence Function)、群間比較の Grayの検定(Gray’s test)、多変量解析である Fine-Grayモデル、最新のRパッケージ tidycmprsk による実践、そして論文でそのまま使える英文テンプレートまでを徹底的に解説する。
1. なぜ他病死を「打切り」にすると過大評価(Overestimate)が起きるのか?
「通常の打切り」と「競合リスク」の致命的な違い
1-KM(1 – Kaplan-Meier)曲線や通常のCox比例ハザードモデルが前提としている「打切り(右側打切り)」は、独立打切り(Independent censoring) と呼ばれる。これは「たまたま研究期間が終了した」「引っ越しで追跡不能になった」など、「もし追跡を続けられていれば、将来的に目的イベントが発生していたかもしれない」 という仮定である。
しかし、「がん特異死亡」を目的イベントとした場合、途中で「他病死(例:肺炎死)」した患者はどうだろうか?
死亡した時点で、その患者が将来「がん特異死亡」を起こす可能性は物理的にゼロになる。これを「もし追跡できていれば将来がん死したかもしれない人(打切り)」として扱うのは、統計学的な前提条件そのものに違反しているのである。
分母(At-risk population)が削られる過大評価のメカニズム
なぜ他病死を打切りにすると、イベント率が高く見積もられてしまうのか?その理由は、計算の分母(リスク集合: Risk set)の削られ方にある。
生存時間解析では、各タイムポイントにおいて「まだイベントを起こしておらず、生存している人数(分母)」に対して「その時点でイベントを起こした人数(分子)」の割合を計算し、累積していく。
他病死した患者を「打切り」に指定すると、その患者は「観察終了」として分母から除外(消去) される。
- 実際の世界: 他病死した患者は「がん死を起こさない確定者」として存在している。
- 1-KMの世界: 他病死した人を分母から消してしまうため、「生き残っている分母(At-risk人数)」が実際よりも早く小さくなる。
分子(がん死した人数)が変わらないのに、分母だけが実際よりも早く減ってしまうため、割り算の結果(累積発現率)が跳ね上がり、本来の確率よりも著しく過大評価(Overestimate)されてしまうのである。
特に、高齢者コホートや長期間の追跡研究など、他病死の割合が高い研究になればなるほど、このバイアス(KM-bias)は無視できないほど巨大になる。
2. 正しい累積イベント発現率を描く「CIF(累積発生関数)」と「Grayの検定」
解決策:累積発生関数(CIF: Cumulative Incidence Function)
競合リスクが存在するデータにおいて、正しいイベント発現率を描くための唯一の正攻法が 累積発生関数(CIF: Cumulative Incidence Function) である。
Kaplan-Meier法が「全員が目的イベントを起こすか生き残るか」の2択しか想定していないのに対し、CIFは「生存」「目的イベント(がん死)」「競合イベント(他病死)」 の3要素を同時に考慮して計算する。
CIFの最大の特徴は、以下の整合性が常に保たれる点にある。$$\text{全生存率} + \text{CIF}_1(\text{目的イベント}) + \text{CIF}_2(\text{競合イベント}) = 100\%$$
他病死した人を「分母に残したまま、他病死イベントとして正しくカウント」するため、分母が不当に削られることがなく、目的イベントの真の発現率を正確に描画することができる。
群間比較の検定:Grayの検定(Gray’s test)
Kaplan-Meier曲線において2群間の生存曲線を比較する際は「ログランク検定(Log-rank test)」を用いるのが一般的である。しかし、競合リスクが存在するCIF曲線に対してログランク検定を適用することはできない。
競合リスク下での群間比較には、Grayの検定(Gray’s test) を使用するのがグローバルスタンダード(鉄則)である。
Grayの検定は、競合イベントの発生確率を適切に重み付けしながら、目的イベントの累積発生関数(CIF)に群間差があるかどうかを正しく検定してくれる。
3. 競合リスク下の多変量解析「Fine-Gray(Subdistribution Hazard)モデル」
Fine-Grayモデルの概念と臨床的意義
臨床研究では、単変量でのCIF描画(Grayの検定)だけでなく、背景因子(年齢、性別、病期など)を調整した多変量解析を行いたい場面が必ず訪れる。
通常のCox比例ハザードモデルで他病死を打切りにするとバイアスが生じるため、競合リスクに対応したモデルが必要となる。そこで用いられるのが Fine-Grayモデル(Subdistribution Hazard Model) である。
Fine-Grayモデルの最大の特徴は、「競合イベント(他病死)を起こした患者を、それ以降の時間帯でも分母(リスク集合)に仮想的に残し続ける」 という特殊な計算を行う点にある。
通常のCox回帰では、イベント発生者や打切り者は分母から即座に消去される。しかしFine-Grayモデルでは、「他病死した人」を「目的イベント未発生者(分母の構成員)」としてペナルティ的に分母に残し続ける。
これにより算出されるハザード比は Subdistribution Hazard Ratio(SHR) と呼ばれ、「CIF(累積発生関数)の高さの差」と直接連動する という非常に強力な臨床的性質を持つ。
- SHR > 1.0: 背景因子を調整しても、その群(またはリスク因子)は目的イベントの累積発現率(CIF)を上昇させる。
- SHR < 1.0: 目的イベントの累積発現率(CIF)を低下させる。
患者に「将来的に目的イベントがどのくらいの確率で起こりそうか」という予後予測や累積発生率の評価を提示したい場合、Fine-GrayモデルによるSHRの提示が必須となる。
4. 【実践Rコード】tidycmprsk によるCIF曲線描画とFine-Grayモデル(Step by Step)
ここからは、最新の標準パッケージである tidycmprsk および ggsurvfit(tidyverse ファミリー)を用いて、競合リスク解析をStep by Stepで実行する手順を解説する。
クラシックな cmprsk パッケージよりもはるかに直感的で、美しいリスクテーブル付きグラフや論文用テーブルが簡単に作成できる。
Step 1: 疑似臨床データの作成と確認
新治療群(New)と標準治療群(Standard)の2群において、時間(time)とイベントステータス(status)を持つ疑似データを生成する。
status = 0: 打切り(Censoring: 追跡終了・生存)status = 1: 目的イベント(Target Event: 例:がん特異死亡)status = 2: 競合イベント(Competing Event: 例:他病死)
library(tidyverse)
library(tidycmprsk)
library(ggsurvfit)
# 乱数シードの設定
set.seed(123)
n <- 300
# 疑似臨床データの作成
df_competing <- tibble(
id = 1:n,
group = factor(rep(c("Standard", "New"), each = n / 2), levels = c("Standard", "New")),
age = round(rnorm(n, mean = 68, sd = 8)),
# 生存時間の生成
time = round(runif(n, min = 1, max = 60), 1),
# 確率的にステータスを付与(0:打切り, 1:目的イベント, 2:競合イベント)
status_code = sample(c(0, 1, 2), size = n, replace = TRUE, prob = c(0.3, 0.4, 0.3))
) %>%
mutate(
# statusをファクター型(ラベル付き)に変換(tidycmprskの推奨表記)
status = factor(status_code, levels = c(0, 1, 2), labels = c("censor", "cancer_death", "other_death"))
)
# データの先頭を確認
head(df_competing)
Step 2: 累積発生関数(CIF)の描画とGrayの検定(tidycmprsk::cuminc)
tidycmprsk::cuminc() 関数を用いてCIFを計算し、ggcuminc() で視覚化する。Grayの検定の $P$ 値も自動的に算出・表示できる。
# CIF(累積発生関数)の計算
cif_fit <- cuminc(Surv(time, status) ~ group, data = df_competing)
# 結果のサマリー表示(Grayの検定 P値含む)
cif_fit
# ggcuminc を用いた洗練されたCIF曲線の描画
cif_fit %>%
ggcuminc(outcome = "cancer_death") + # 描画したい目的イベントを指定
add_confidence_interval() + # 95%信頼区間の帯を追加
add_risktable() + # リスクテーブル(At-risk人数)を追加
add_pvalue() + # Grayの検定 P値を表示
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) + # Y軸をパーセント表記に調整
labs(
x = "Months",
y = "Cumulative Incidence of Cancer Death",
title = "Cumulative Incidence Function (CIF) by Treatment Group"
) +
scale_ggsurvfit()

Step 3: Fine-Grayモデルの実行とハザード比(SHR)の算出
背景因子(group および age)を調整した多変量 Fine-Grayモデルを実行する。tidycmprsk::crr() 関数を使用する。
# Fine-Grayモデル(Subdistribution Hazard Model)の実行
fg_model <- crr(Surv(time, status) ~ group + age, data = df_competing, failcode = "cancer_death")
# モデル結果の表示(Subdistribution Hazard Ratio: SHR と 95% CI)
fg_model
# gtsummary を用いた論文表示用テーブルの作成
fg_model %>%
tbl_regression(exponentiate = TRUE)

5. 論文でそのまま使える英文テンプレート(Methods & Results)
論文(MethodsおよびResultsセクション)にそのまま記述できる標準的な英文表現テンプレートを提示する。
Methods セクション英文テンプレート
“To evaluate the cumulative incidence of [target event, e.g., cancer-specific mortality] in the presence of competing risks (e.g., non-cancer deaths), the cumulative incidence function (CIF) was estimated for each group and compared using Gray’s test. Non-cancer death was treated as a competing risk rather than an independent censoring event to avoid overestimation of the event rate. For multivariable analysis adjusting for potential confounders, Fine-Gray subdistribution hazard models were fitted to estimate subdistribution hazard ratios (SHRs) and their 95% confidence intervals (CIs). All statistical analyses were performed using R (version 4.x.x) with the
tidycmprskpackage.”
Results セクション英文テンプレート
“During the follow-up period, [40] patients experienced [cancer-specific death] and [30] patients died from competing causes. The 5-year cumulative incidence of [cancer-specific death] estimated by the CIF was [24.5]% (95% CI, [18.2]% to [31.5]%) in the [New Treatment] group compared with [38.2]% (95% CI, [30.1]% to [46.3]%) in the [Standard Treatment] group (Gray’s test,$P = 0.018$). In the multivariable Fine-Gray model adjusting for age and baseline covariates, [New Treatment] was associated with a significantly lower risk of [cancer-specific death] (Subdistribution Hazard Ratio [SHR], [0.58]; 95% CI, [0.37] to [0.91];$P = 0.018$).”
まとめ&一括コピペ用Rスクリプト
本記事のポイントおさらい
- 他病死を単なる「打切り」にして描いた1-KM曲線は即却下: 分母(リスク集合)が不当に削られ、累積イベント発生率が著しく過大評価(Overestimate)される。
- 正攻法はCIF(累積発生関数)+ Grayの検定: 競合イベントを正しくカウントし、全生存率+目的イベント発生率+競合イベント発生率の合計が100%になる整合性を保つ。
- 多変量解析はFine-Grayモデル: 競合イベント発生者を分母に残し続けることで、実際の累積発生率(CIF)の高さと直結する Subdistribution Hazard Ratio(SHR)を算出する。
一括実行用Rスクリプト
以下のコードをコピー&ペーストすることで、疑似データの生成からCIF描画、Grayの検定、Fine-Grayモデルの実行、論文用サマリー出力までを一気通貫で実行できる。
# ==============================================================================
# 競合リスク生存時間解析(CIF & Fine-Gray Model)一括実行スクリプト
# パッケージ: tidycmprsk, ggsurvfit, tidyverse
# ==============================================================================
# 必要なライブラリの読み込み
if (!requireNamespace("tidycmprsk", quietly = TRUE)) install.packages("tidycmprsk")
if (!requireNamespace("ggsurvfit", quietly = TRUE)) install.packages("ggsurvfit")
if (!requireNamespace("gtsummary", quietly = TRUE)) install.packages("gtsummary")
library(tidyverse)
library(tidycmprsk)
library(ggsurvfit)
library(gtsummary)
# 1. 疑似臨床データの作成
set.seed(123)
n <- 300
df_competing <- tibble(
id = 1:n,
group = factor(rep(c("Standard", "New"), each = n / 2), levels = c("Standard", "New")),
age = round(rnorm(n, mean = 68, sd = 8)),
time = round(runif(n, min = 1, max = 60), 1),
status_code = sample(c(0, 1, 2), size = n, replace = TRUE, prob = c(0.3, 0.4, 0.3))
) %>%
mutate(
status = factor(status_code, levels = c(0, 1, 2), labels = c("censor", "target_event", "competing_event"))
)
# 2. 累積発生関数(CIF)の計算とGrayの検定
cat("\n--- 累積発生関数(CIF)とGrayの検定結果 ---\n")
cif_fit <- cuminc(Surv(time, status) ~ group, data = df_competing)
print(cif_fit)
# 3. CIF曲線の描画
p_cif <- cif_fit %>%
ggcuminc(outcome = "target_event") +
add_confidence_interval() +
add_risktable() +
add_pvalue() +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
labs(
x = "Follow-up Time (Months)",
y = "Cumulative Incidence of Target Event",
title = "Cumulative Incidence Function (CIF) with Competing Risks"
) +
scale_ggsurvfit()
# グラフの表示
print(p_cif)
# 4. 多変量 Fine-Gray モデルの実行
cat("\n--- Fine-Gray モデル (Subdistribution Hazard Ratio) ---\n")
fg_model <- crr(Surv(time, status) ~ group + age, data = df_competing, failcode = "target_event")
print(fg_model)
# 5. 論文表示用テーブルの作成
tbl_fg <- fg_model %>%
tbl_regression(exponentiate = TRUE)
print(tbl_fg)





コメント