MENU

【無料プレゼント付き】学会発表・論文投稿に必要な統計を最短で学ぶことができる無料メルマガ

【R言語】3群以上の生存時間データをIPTW解析する方法!重み付きKM曲線描画からCox回帰(HR算出)まで完全攻略

研究者: 3群以上(例:「標準治療 vs 治療A vs 治療B」)ある治療群の生存時間データで交絡調整を行いたいのですが、傾向スコア重み付け(IPTW)のコードや重み付きカプランマイヤー曲線の描き方が分かりません……。

統計ER: 3群以上の多群(Multi-treatment)になっても身構える必要はありません!WeightIt + cobalt + survival + survminer を使えば、2群比較とほとんど変わらないシンプルな記述で一般化傾向スコアの重み計算からKM曲線描画・Cox回帰(ハザード比算出)まで完結できますよ!さっそく解説しましょう!

臨床研究や観察研究(リアルワールドデータ解析)において、治療法や曝露因子が3群以上(例:「標準治療 vs 新薬A vs 新薬B」「低用量 vs 中用量 vs 高用量」など)存在し、交絡因子を調整した上でカプランマイヤー(KM)生存曲線を描画したりCox比例ハザードモデルでハザード比(HR)を算出したい場面は非常に多い。

2群間の傾向スコア逆確率重み付け(IPTW: Inverse Probability of Treatment Weighting)の手順はWeb上に多く存在するが、3群以上の多群(Multi-treatment)比較になると、傾向スコアの計算や重み付けのコードで途端に詰まってしまう研究者が少なくない。

「多項ロジスティック回帰で一般化傾向スコアを手算出しなければならないのか?」と身構える必要はない。Rの強力なパッケージ群を組み合わせれば、3群以上の生存時間解析であっても、2群比較とほとんど変わらないシンプルな記述で完結できる。

本記事では、WeightItcobaltsurvivalsurvminer パッケージを活用し、3群以上の生存時間データにおける重み計算・バランス評価・重み付きKM曲線描画・重み付きCox回帰(HR算出)までを一気通貫で解説する。

>>もう統計で悩むのは終わりにしませんか? 

↑1万人以上の医療従事者が購読中

目次

3群以上における傾向スコア(一般化傾向スコア:GPS)とIPTWの基本ルール

2群比較における傾向スコアは「治療群に割り当てられる条件付き確率(二項ロジスティック回帰)」であったが、治療法が3群以上($K \ge 3$)に増えた場合、一般化傾向スコア(Generalized Propensity Score: GPS)の概念が適用される。

GPSでは、多項ロジスティック回帰モデル(Multinomial Logistic Regression)などを用いて、患者の共変量 $X$ のもとで各治療群 $k$ を受ける事後確率 $P(A = k \mid X)$ を算出する。

そして、各症例に対して「実際に受けた治療群 $k$ に割り当てられた確率の逆数」を重み(ATE重み: Inverse Probability Weight)として割り当てる。$$w_i = \frac{1}{P(A = a_i \mid X_i)}$$

数式は複雑に見えるが、Rにおいてはパッケージが裏側で自動的に多項モデルをフィッティングしてくれるため、ユーザーが手動で確率計算を行う必要はない。

使用する神パッケージ4選とパイプラインの役割

3群以上の生存時間IPTW解析をスムーズに行うため、以下の4つのパッケージを連携させる。

  • WeightIt: 治療変数が3群以上の因子型(factor)であっても、自動的に多項モデルを適用して一括でIPTW重みを計算してくれる万能パッケージ。
  • cobalt: 3群間の全ペア(Pairwise)における標準化平均差(SMD)を一括評価する。
  • survival: 重み付きカプランマイヤー推定量(survfit)および重み付きCox比例ハザードモデル(coxph)を実行する。
  • survminer: 論文掲載レベルの美しく整った多群カプランマイヤー曲線(ggsurvplot)を描画する。

>>もう統計で悩むのは終わりにしませんか? 

↑1万人以上の医療従事者が購読中

【実践ステップ】Rで3群以上の生存時間データをIPTW解析する全コード

ここからは、実際にR環境で動作するサンプルコードを用いて、Step 1からStep 5まで順番に解説する。

まずは必要なパッケージを読み込んでおこう。

# 必要なパッケージの読み込み
library(tidyverse)
library(WeightIt)
library(cobalt)
library(survival)
library(survminer)

Step 1: サンプルデータ(3群の生存時間データ)の準備

動作確認用として、3つの治療群(Group_A, Group_B, Group_C)と生存時間(time)、イベント有無(status)、共変量を含むサンプルデータを作成する。

# サンプルデータの作成(3群比較)
set.seed(123)
n <- 400

df_surv <- tibble(
  id    = 1:n,
  # 3群の治療変数(Factor型で定義)
  treat = factor(sample(c("Group_A", "Group_B", "Group_C"), n, replace = TRUE, prob = c(0.4, 0.3, 0.3))),
  age   = rnorm(n, mean = 65, sd = 10),
  sex   = factor(sample(c("Male", "Female"), n, replace = TRUE)),
  bmi   = rnorm(n, mean = 24, sd = 4),
  sbp   = rnorm(n, mean = 135, sd = 15),
  # 追跡時間とイベント(1: 発生, 0: 打切り)
  time   = round(runif(n, min = 1, max = 60), 1),
  status = sample(c(0, 1), n, replace = TRUE, prob = c(0.6, 0.4))
)

head(df_surv)

Step 2: WeightIt による重み付け(一般化傾向スコア)

WeightIt パッケージの weightit() 関数は、目的変数(治療変数)が3群以上の因子型(factor)になっている場合、自動的に多項モデル(method = "glm")を選択して各群の一般化傾向スコアとIPTW重みを算出する。

# 3群に対するIPTW重みの計算
W_multi <- weightit(
  treat ~ age + sex + bmi + sbp,
  data     = df_surv,
  method   = "glm",       # 多項ロジスティック回帰が内部で適用される
  estimand = "ATE"        # ATE重みを指定
)

# 重みオブジェクトの確認
summary(W_multi)

2群比較のコードと全く同じ構文で3群の重み付けが完了する点が、WeightIt を使う最大のメリットである。

Step 3: 3群間の共変量バランス評価(cobalt::bal.tab

3群以上の解析では、各治療群のペアすべて(Group A vs B、Group A vs C、Group B vs C)における標準化平均差(Pairwise SMD) がバランスの評価対象となる。

cobalt パッケージの bal.tab() を使用すれば、全ペアの最大SMD(Max SMD)や統合結果を一括で確認できる。

# 3群間の共変量バランス(SMD)を一括評価
bal.tab(W_multi, un = TRUE, stats = c("m"), thresholds = c(m = 0.1))

出力結果において、重み付け後(Adj)の最大SMD(Max.Diff.Adj)がすべて 0.1 未満 に収まっていれば、3群間での共変量バランス調整は成功である。

Step 4: 重み付きカプランマイヤー(KM)曲線の描画(survminer

重み付け調整後の生存確率を推定し、カプランマイヤー曲線を描画する。

survival::survfit()weights 引数に算出された重み(W_multi$weights)を渡すことで、簡単に重み付きKM推定量を算出できる。

# 重み付きカプランマイヤー曲線の推定
fit_km <- survfit(
  Surv(time, status) ~ treat,
  data    = df_surv,
  weights = W_multi$weights
)

# survminer による多群KM曲線の描画
ggsurvplot(
  fit_km,
  data           = df_surv,
  pval           = TRUE,             # ログランク検定P値の表示
  risk.table     = TRUE,             # Risk Tableの表示
  legend.title   = "Treatment",
  legend.labs    = c("Group A", "Group B", "Group C"),
  palette        = c("#E41A1C", "#377EB8", "#4DAF4A"), # カラーパレット
  title          = "Weighted Kaplan-Meier Survival Curves (3 Groups)",
  xlab           = "Time (Months)",
  ylab           = "Overall Survival Probability"
)

調整前の背景バイアスが取り除かれた、美しく信頼性の高い3群比較の生存曲線が出力される。

Step 5: 重み付きCox比例ハザードモデルによるハザード比(HR)算出

各治療群間のハザード比(HR)および95%信頼区間を算出するため、重み付きCox比例ハザードモデルを実行する。

IPTWを適用した疑似集団における回帰分析では、標準誤差が過小評価されるのを防ぐため、堅牢な標準誤差(Robust Standard Error / Sandwich Estimator) を指定する必要がある。coxph() 内で robust = TRUE または cluster = id を指定する。

# 重み付きCox比例ハザードモデルの実行
fit_cox <- coxph(
  Surv(time, status) ~ treat,
  data    = df_surv,
  weights = W_multi$weights,
  robust  = TRUE             # 堅牢な標準誤差を算出
)

# 解析結果(ハザード比と95%CI)の表示
summary(fit_cox)

出力結果の解釈:

基準群(デフォルトではアルファベット順の第1水準 Group_A)に対する Group_B および Group_C のハザード比(exp(coef))とその95%信頼区間・P値が出力される。

3群以上のIPTW解析で気をつけたい注意点

1. 極端な重み(Extreme Weights)への対処

群数が3群、4群と増えるにつれ、一般化傾向スコアの推定値が0に極めて近い症例が発生しやすくなり、極端に大きな重み(Extreme Weights) が生じるリスクが高まる。

もし特定症例の重みが突出して大きい場合は、WeightIt 内のトリミング機能(例: trim(W_multi, at = 0.99))や、安定化重み(Stabilized Weights)の検討を行うことが推奨される。

2. ハザード比の基準群(Reference)の指定

3群比較では「どの治療群を対照(基準)としてハザード比を算出するか」をあらかじめ決定しておく必要がある。

意図した群(例: 標準治療群)を基準に設定したい場合は、解析前に forcats::fct_relevel()relevel() を使って因子水準(Factor Levels)の第1水準に指定しておこう。

# Group_A を基準群(Reference)に明示的に設定
df_surv <- df_surv %>% 
  mutate(treat = fct_relevel(treat, "Group_A"))

【まとめ】コピペで動く一括テンプレートコード

最後に、本記事で紹介した「3群以上の生存時間データに対するIPTW解析」の一式コードをまとめた。自身のデータセット名・変数名に書き換えてコピー&ペーストで活用してほしい。

# === 3群以上の生存時間データ IPTW解析 一括テンプレート ===
library(tidyverse)
library(WeightIt)
library(cobalt)
library(survival)
library(survminer)

# 1. 基準群の整理(必要に応じて基準群を第1水準に設定)
df <- df_surv %>% 
  mutate(treat = fct_relevel(treat, "Group_A"))

# 2. IPTW重み(一般化傾向スコア)の計算
W <- weightit(
  treat ~ age + sex + bmi + sbp, # 治療変数 ~ 共変量
  data     = df,
  method   = "glm",
  estimand = "ATE"
)

# 3. 3群間の共変量バランス評価(SMD < 0.1 の確認)
bal.tab(W, un = TRUE, thresholds = c(m = 0.1))

# 4. 重み付きカプランマイヤー曲線の推定と描画
fit_km <- survfit(Surv(time, status) ~ treat, data = df, weights = W$weights)
ggsurvplot(fit_km, data = df, pval = TRUE, risk.table = TRUE)

# 5. 重み付きCox回帰(ハザード比の算出)
fit_cox <- coxph(Surv(time, status) ~ treat, data = df, weights = W$weights, robust = TRUE)
summary(fit_cox)

難解に見える多群の生存時間因果推論も、WeightItsurvivalsurvminer のパイプラインを使えば非常にスマートに処理できる。

適切な交絡調整を行い、説得力の高い臨床研究結果を発表していこう。

おすすめ書籍

誰も教えてくれなかった 医療統計の使い分け〜迷いやすい解析手法の選び方が,Rで実感しながらわかる!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

リサーチクエスチョン探し?データ分析?論文投稿?、、、で、もう悩まない!

第1章臨床研究ではなぜ統計が必要なのか?計画することの重要性
  • 推定ってどんなことをしているの?
  • 臨床研究を計画するってどういうこと?
  • どうにかして標本平均を母平均に近づけられないか?
第2章:研究目的をどれだけ明確にできるのかが重要
  • データさえあれば解析でどうにかなる、という考え方は間違い
  • 何を明らかにしたいのか? という研究目的が重要
  • 研究目的は4種類に分けられる
  • 統計専門家に相談する上でも研究目的とPICOを明確化しておく
第3章:p値で結果が左右される時代は終わりました
  • アメリカ統計協会(ASA)のp値に関する声明で指摘されていること
  • そうは言っても、本当に有意差がなくてもいいの…?
  • なぜ統計専門家はp値を重要視していないのか
  • 有意差がない時に「有意な傾向があった」といってもいい?
  • 統計を放置してしまうと非常にまずい
第4章:多くの人が統計を苦手にする理由
  • 残念ながら、セミナー受講だけで統計は使えません。
  • インプットだけで統計が使えない理由
  • どうやったら統計の判断力が鍛えられるか?
  • 統計は手段なので正解がないため、最適解を判断する力が必要
第5章:統計を使えるようになるために今日から何をすれば良いか?
  • 論文を読んで統計が使えるようになるための5ステップ
第6章:統計を学ぶために重要な環境
  • 統計の3つの力をバランスよく構築する環境

以下のボタンをクリックして、画面に出てくる指示に従って、必要事項を記入してください。

この記事を書いた人

医師、医学博士(専門は疫学および統計学)。10年以上の研究歴を有し、筆頭著者として10本の英文原著論文を執筆した実績を持つ。現在、外資系製薬企業にて15年以上にわたり、臨床開発やデータ解析、承認審査、薬価交渉戦略といった実務の最前線に従事。

「統計に悩むあなたを救いたい」をコンセプトに、ブログ「統計ER」やYouTube、SNSを通じて、医療従事者や研究者向けに「実務直結の統計ノウハウ」を配信。

学術的な厳密さと、製薬業界での高度な実務経験を融合させた独自の視点から、ブラックボックス化しない統計解析の普及を目指す。オンラインショップ「TKER SHOP」での計算ツール提供や、クラウドワークス等を通じた統計コンサルティング・解析代行(主にRを使用)も幅広く展開中。

コメント

コメントする

目次