「先生!低侵襲な新手術と標準手術の全生存期間(OS)を比較したところ、$P = 0.32$ で有意差なしでした!つまり、新手術の非劣性が証明されたということですよね?早速論文を書こうと思います!」
……ちょっと待ってほしい。それは論文査読(Peer Review)において、査読者から一発で却下される最も危険な誤用である。
臨床現場や学会発表において、「$P > 0.05$(有意差なし)= 差がない = 非劣性である」と解釈してしまうケースは後を絶たない。しかし、仮説検定の論理構造上、通常の優越性試験における「有意差なし」は決して非劣性の証明にはならない。
本記事では、生存時間解析においてなぜ $P > 0.05$ では非劣性を主張できないのかという理論的背景から、国際ガイドライン(ICH-E9)に準拠した95%信頼区間上限($\text{CI}_{\text{upper}}$)と非劣性マージン($\Delta$)による正当な判定ルール、ITT解析とPP解析の二重検証、そしてRでの実践コードおよび論文でそのまま使える英文テンプレートまでを徹底的に解説する。
第1章:なぜ「P > 0.05(有意差なし)」で非劣性を主張してはいけないのか?
仮説検定の論理的限界:「証明の不在」と「不在の証明」
通常の優越性試験(Superiority trial)で設定される帰無仮説は、「両群のハザードに差がない(ハザード比 $\text{HR} = 1.0$)」というものである。
この検定において $P > 0.05$ となり帰無仮説が棄却できなかった場合、得られた結論は「両群に差があるとは言い切れなかった」に過ぎない。これは「差がないことが証明された(Proof of Absence)」のではなく、単に「差がある証拠が得られなかった(Absence of Proof)」状態を示している。
例えば、単にサンプルサイズが不足している(検出力が低い)不十分な臨床研究であっても、$P > 0.05$ という結果は容易に得られてしまう。データが不十分で精度が低いだけの解析を「差がない(非劣性である)」と解釈してしまうことが、どれほど危険か理解できるだろう。
非劣性試験における正当な仮説設定
非劣性を証明するためには、「差がない」ことを帰無仮説にするのではなく、「許容できないほど悪化している(劣性である)」ことを帰無仮説に設定する必要がある。
新治療群のイベント発生ハザードが標準治療群に対して低くなること($\text{HR} < 1.0$)を「臨床的に望ましい(リスク低下)」とする場合、臨床的に「これ以上の悪化であれば許容できる」という限界値として非劣性マージン $\Delta$(通常 $\Delta > 1.0$)を設定する。
このとき、非劣性試験の仮説設定は以下のように厳格に定義される。$$H_0: \text{HR} \ge \Delta \quad \text{vs} \quad H_1: \text{HR} < \Delta$$
- 帰無仮説($H_0$): 劣性である(新治療のハザードが許容限界 $\Delta$ 以上に悪化している)
- 対立仮説($H_1$): 非劣性である(新治療のハザード悪化は許容限界 $\Delta$ 未満にとどまっている)
この帰無仮説 $H_0$ を統計的に棄却できて初めて、「非劣性が証明された」と胸を張って主張できるのである。
第2章:非劣性判定の絶対ルール「95%信頼区間上限」と「マージン $\Delta$」
95%信頼区間法(Confidence Interval approach)
生存時間解析における非劣性の判定は、$P$ 値ではなく、Cox比例ハザードモデルから算出されるハザード比の両側95%信頼区間の上限値($\text{CI}_{\text{upper}}$)が非劣性マージン $\Delta$ を下回っているかどうかで判断する。
- 非劣性成立の判定条件: $\text{CI}_{\text{upper}} < \Delta$
視覚的イメージ(判定の3パターン)
非劣性マージンを $\Delta = 1.30$(標準治療に対してハザードの30%増加まで許容)と設定した場合の、信頼区間による判定パターンは以下の通りである。
[標準治療有利] [新治療不利]
|
(1) 非劣性成立 |--- Point ---|| (CI upper < 1.30)
|
(2) 非劣性不成立 |------ Point ------| (CI upper >= 1.30)
|
(3) 非劣性+優越性成立 |--Point--| | (CI upper < 1.0)
|
HR=1.0 Δ=1.30
- 非劣性成立(Non-inferiority):
- 条件: $\text{CI}_{\text{upper}} < \Delta$(かつ $\text{CI}_{\text{upper}} \ge 1.0$)
- 解釈: 95%信頼区間の上限がマージン $\Delta$ を下回っている。仮に新治療でハザードが悪化していたとしても、その程度は許容限界(30%増)未満であることが統計的に示された。
- 非劣性不成立(Inconclusive for Non-inferiority):
- 条件: $\text{CI}_{\text{upper}} \ge \Delta$
- 解釈: たとえ点推定値(HR)が $1.0$ 未満(例: $\text{HR} = 0.95$)であっても、$\text{CI}_{\text{upper}}$ が $1.35$ などでマージンを超えている場合、非劣性は証明されない。「許容できないほど悪化している可能性」を排除し切れていないためである。
- 非劣性 + 優越性の成立(Superiority):
- 条件: $\text{CI}_{\text{upper}} < 1.0$
- 解釈: 95%信頼区間の上限が $1.0$ すら下回っている。新治療が標準治療に対して非劣性であるばかりか、統計的に有意に優れている(優越性)ことが同時に証明された。
スイッチング(1/2ステップ)ルール
研究プロトコルにおいてあらかじめ事前規定(Pre-specification)されていれば、非劣性試験としてデザイン・解析を行ったデータにおいて非劣性が証明された($\text{CI}_{\text{upper}} < \Delta$)後、同じデータを用いて優越性($\text{CI}_{\text{upper}} < 1.0$)の評価へ移行することが臨床試験のルール上認められている。
この際、多重性(Multiplicity)が生じないため、第一種の誤り率($\alpha$ エラー)の調整を行うことなく、そのまま優越性を評価・主張して差し支えない。
第3章:非劣性試験における「ITT解析」の罠と「PP解析」の必須性(ICH-E9)
優越性試験と非劣性試験でのバイアスの向き
臨床試験の解析対象集団には、割付通りに全症例を解析する ITT(Intention-to-Treat)集団 と、プロトコル違反者を除外した PP(Per-Protocol)集団 が存在する。
両試験におけるバイアスの働く方向の違いは以下の通りである。
- 優越性試験におけるITT解析: 服薬不遵守やドロップアウトなどのノイズが含まれるため、両群間の差が薄まる方向($\text{HR} \to 1.0$)へ働く。これは「差がある」と主張したい優越性試験においては結果を保守的(Safe側)にするため、優越性試験ではITT解析が主解析(Primary Analysis)とされる。
- 非劣性試験におけるITT解析: 両群間の差が薄まる方向($\text{HR} \to 1.0$)に働くことは、「両群に差がない=非劣性である」という結論を導きやすくする。つまり、ITT解析は非劣性試験において結果を非保守的(Unsafe側 / 非劣性を示しやすくする方向)にバイアスさせる。
ICH-E9ガイドラインに基づく二重検証(Dual Evaluation)
日米EU医薬品規制調和国際会議(ICH-E9ガイドライン)では、非劣性試験におけるこのバイアスリスクを防止するため、ITT解析とPP解析の両方を実施し、双方の解析で一貫して非劣性が示されること(Dual Evaluation)を強く求めている。
主解析をITTで行う場合でも、必ずPP集団による感度分析(Sensitivity Analysis)を行い、結論が揺るがないことを示す必要がある。
第4章:【実践Rコード】Cox比例ハザードモデルによる非劣性解析(Step by Step)
ここからは、Rを用いてCox比例ハザードモデルによる非劣性生存時間解析を実行する手順を解説する。
Step 1: 疑似臨床データの作成と確認
survival パッケージおよび tidyverse を使用し、新治療群(New)と標準治療群(Standard)の生存時間データを生成する。
library(survival)
library(tidyverse)
# 乱数シードの設定
set.seed(123)
n <- 400
# 疑似臨床データの作成
df <- tibble(
id = 1:n,
group = factor(rep(c("Standard", "New"), each = n / 2), levels = c("Standard", "New")),
# 生存時間(月)の生成
futime = round(rexp(n, rate = if_else(rep(c("Standard", "New"), each = n / 2) == "Standard", 0.03, 0.032)) * 12, 1),
event = rbinom(n, size = 1, prob = 0.7),
itt = 1,
# 10%のプロトコル違反者(PPから除外)
pp = if_else(runif(n) > 0.10, 1, 0)
) %>%
mutate(
status = if_else(futime > 60, 0, event),
time = if_else(futime > 60, 60, futime)
)
# データの先頭を確認
head(df)
Step 2: Kaplan-Meier曲線の描画
生存曲線の視覚的推移を確認する。
※補足(関連記事)
なお、Cox比例ハザードモデルの前提条件である比例ハザード性の確認(Schoenfeld残差プロット)については、[過去記事:Cox回帰での比例ハザード性破綻とRMST] を参照されたい。
library(survminer)
# ITT集団でのKaplan-Meier曲線の作成
fit_km <- survfit(Surv(time, status) ~ group, data = df)
# グラフ描画
ggsurvplot(
fit_km,
data = df,
pval = FALSE, # 通常のP値(H0: HR=1.0)は描画しない
conf.int = TRUE,
risk.table = TRUE,
legend.labs = c("Standard", "New"),
palette = c("#2E9FDF", "#E7B800"),
title = "Overall Survival (ITT Population)",
xlab = "Time (Months)",
ylab = "Survival Probability"
)

Step 3: Cox比例ハザードモデルの実行と95% CI上限の算出
survival::coxph 関数を用いてCox比例ハザードモデルを構築し、ハザード比(HR)とその両側95%信頼区間の上限値を取得する。
# ITT集団に対するCox比例ハザードモデル
cox_itt <- coxph(Surv(time, status) ~ group, data = df)
sum_itt <- summary(cox_itt)
# ハザード比、標準誤差、両側95%信頼区間の取得
hr_itt <- sum_itt$coefficients["groupNew", "exp(coef)"]
se_itt <- sum_itt$coefficients["groupNew", "se(coef)"]
ci_lower_itt <- sum_itt$conf.int["groupNew", "lower .95"]
ci_upper_itt <- sum_itt$conf.int["groupNew", "upper .95"]
cat(sprintf("ITT Population Results:\n"))
cat(sprintf("HR: %.3f (95%% CI: %.3f - %.3f)\n", hr_itt, ci_lower_itt, ci_upper_itt))
結果は以下のとおり 95% 信頼区間上限値は、1.884 となる。
> cat(sprintf("ITT Population Results:\n"))
ITT Population Results:
> cat(sprintf("HR: %.3f (95%% CI: %.3f - %.3f)\n", hr_itt, ci_lower_itt, ci_upper_itt))
HR: 1.013 (95% CI: 0.545 - 1.884)
Step 4: 非劣性マージン($\Delta = 1.30$)との比較および片側 P 値の算出
非劣性マージンを $\Delta = 1.30$ と設定する。
片側Wald検定による非劣性の $P$ 値($P_{\text{NI}}$)は、以下の数式で得られる $Z$ スコアを用いて算出する。$$Z = \frac{\ln(\text{HR}) – \ln(\Delta)}{\text{SE}(\ln(\text{HR}))}$$
この $Z$ スコアから標準正規分布の累積確率(Rの pnorm 関数)を求めることで、片側非劣性 $P$ 値が計算できる。
# マージンの設定
margin <- 1.30
# 片側検定統計量 Z および P値の計算
z_ni_itt <- (log(hr_itt) - log(margin)) / se_itt
p_ni_itt <- pnorm(z_ni_itt)
cat(sprintf("One-sided P-value for Non-Inferiority: %.4f\n", p_ni_itt))
# 非劣性の判定
if (ci_upper_itt < margin) {
cat("Conclusion: Non-inferiority is ESTABLISHED (CI upper < Margin)\n")
} else {
cat("Conclusion: Non-inferiority is NOT established (CI upper >= Margin)\n")
}
結果は以下のとおり、非劣性確認できず、となる。1.30 が非劣性の限界値と考えたとき、1.884 が 95% 信頼区間上限となると、劣ることがありうるという結論で、非劣性は確認できないわけである。
One-sided P-value for Non-Inferiority: 0.2155
Conclusion: Non-inferiority is NOT established (CI upper >= Margin)
Step 5: ITT集団 vs PP集団の感度分析(Sensitivity Analysis)
ICH-E9に則り、PP集団でも同様の解析を行い、結論の一貫性を評価する。
# PP集団(pp == 1)に対するCox比例ハザードモデル
cox_pp <- coxph(Surv(time, status) ~ group, data = df, subset = (pp == 1))
sum_pp <- summary(cox_pp)
hr_pp <- sum_pp$coefficients["groupNew", "exp(coef)"]
se_pp <- sum_pp$coefficients["groupNew", "se(coef)"]
ci_lower_pp <- sum_pp$conf.int["groupNew", "lower .95"]
ci_upper_pp <- sum_pp$conf.int["groupNew", "upper .95"]
z_ni_pp <- (log(hr_pp) - log(margin)) / se_pp
p_ni_pp <- pnorm(z_ni_pp)
cat(sprintf("\nPP Population Results:\n"))
cat(sprintf("HR: %.3f (95%% CI: %.3f - %.3f)\n", hr_pp, ci_lower_pp, ci_upper_pp))
cat(sprintf("One-sided P-value for Non-Inferiority: %.4f\n", p_ni_pp))
PP集団でも同様の結果であった。
PP Population Results:
HR: 1.052 (95% CI: 0.552 - 2.005)
One-sided P-value for Non-Inferiority: 0.2600
第5章:論文でそのまま使える英文テンプレート(Methods & Results)
論文(MethodsおよびResultsセクション)に記載する際の標準的な英文表現テンプレートを示す。
Methods セクション英文テンプレート
“The primary objective of this study was to evaluate the non-inferiority of [New Treatment] compared to [Standard Treatment] in terms of overall survival (OS). The non-inferiority margin for the hazard ratio (HR) was pre-specified at$\Delta = 1.30$. Hazard ratios and their 95% confidence intervals (CIs) were estimated using a Cox proportional hazards model. Non-inferiority was declared if the upper bound of the two-sided 95% CI for HR was less than 1.30, corresponding to a one-sided significance level of$\alpha = 0.025$. In accordance with the ICH-E9 guidelines, non-inferiority analyses were performed on both the intention-to-treat (ITT) and per-protocol (PP) populations to ensure consistency of the findings.”
Results セクション英文テンプレート
“In the ITT population, the hazard ratio for overall survival in the [New Treatment] group relative to the [Standard Treatment] group was [0.98] (95% CI, [0.75] to [1.24]). The upper bound of the 95% CI ([1.24]) was below the pre-specified non-inferiority margin of 1.30 (one-sided$P$for non-inferiority = [0.012]). Consistent results were observed in the per-protocol analysis (HR [0.96], 95% CI [[0.73] to [1.22]], one-sided$P$for non-inferiority = [0.008]). Thus, [New Treatment] was demonstrated to be non-inferior to [Standard Treatment].”
まとめ&一括コピペ用Rスクリプト
本記事のポイントまとめ
- $P > 0.05$(有意差なし)は非劣性の証明ではない: 単なる検出力不足でも $P > 0.05$ になる。「差があると言い切れない」ことと「差がない」ことは全く別物である。
- 評価基準は95%信頼区間の上限($\text{CI}_{\text{upper}}$): 点推定値ではなく、$\text{CI}_{\text{upper}} < \Delta$(非劣性マージン)を満たすかどうかで判定する。
- ITT解析とPP解析の二重検証が必須(ICH-E9): 非劣性試験ではITT解析が結果を「非劣性側」へバイアスさせるリスクがあるため、PP解析での結果の一致を確認する。
一括実行用Rスクリプト
以下のコードをコピー&ペーストすることで、データ作成からCox比例ハザードモデル実行、非劣性判定、片側 $P$ 値算出、ITT/PP比較出力までを一括して実行できる。
# ==============================================================================
# 非劣性生存時間解析(Non-inferiority Survival Analysis)一括実行スクリプト
# ==============================================================================
library(survival)
library(tidyverse)
# 1. 疑似データの生成
set.seed(123)
n <- 400
df <- tibble(
id = 1:n,
group = factor(rep(c("Standard", "New"), each = n / 2), levels = c("Standard", "New")),
futime = round(rexp(n, rate = if_else(rep(c("Standard", "New"), each = n / 2) == "Standard", 0.03, 0.032)) * 12, 1),
event = rbinom(n, size = 1, prob = 0.7),
itt = 1,
pp = if_else(runif(n) > 0.10, 1, 0)
) %>%
mutate(
status = if_else(futime > 60, 0, event),
time = if_else(futime > 60, 60, futime)
)
# 2. 解析設定
margin <- 1.30 # 非劣性マージン Δ
# 3. 解析関数定義
analyze_non_inferiority <- function(data, pop_name, subset_condition = NULL) {
if (!is.null(subset_condition)) {
sub_data <- data %>% filter(eval(parse(text = subset_condition)))
} else {
sub_data <- data
}
fit <- coxph(Surv(time, status) ~ group, data = sub_data)
s <- summary(fit)
hr <- s$coefficients["groupNew", "exp(coef)"]
se <- s$coefficients["groupNew", "se(coef)"]
ci_lower <- s$conf.int["groupNew", "lower .95"]
ci_upper <- s$conf.int["groupNew", "upper .95"]
# 片側P値の算出
z <- (log(hr) - log(margin)) / se
p_val <- pnorm(z)
ni_status <- if_else(ci_upper < margin, "Non-inferiority Established", "NOT Established")
return(tibble(
Population = pop_name,
N = nrow(sub_data),
HR = round(hr, 3),
`95% CI Lower` = round(ci_lower, 3),
`95% CI Upper` = round(ci_upper, 3),
`Margin (Delta)` = margin,
`One-sided P (NI)` = round(p_val, 4),
`Conclusion` = ni_status
))
}
# 4. ITTおよびPP解析の実行と結果表示
results_itt <- analyze_non_inferiority(df, "ITT Population")
results_pp <- analyze_non_inferiority(df, "PP Population", subset_condition = "pp == 1")
final_summary <- bind_rows(results_itt, results_pp)
cat("\n==============================================================================\n")
cat(" NON-INFERIORITY ANALYSIS SUMMARY \n")
cat("==============================================================================\n\n")
print(as.data.frame(final_summary))
cat("\n==============================================================================\n")





コメント