powerの分布を考えてみよう
モチベ: 様々な真の値に対するpowerの分布を計算したい。
“真のリスク比” なんて神のみぞ知る値。powerの計算ってどれくらいrobustnessがあるのかな?という関心です。
- 曝露変数: 0/1の2値、結果変数: 0/1の2値、のシチュエーション
- 真のリスク比を与えられるとpowerを返す関数を作り、リスク比に対するpowerの関係を可視化したい
真の値と言っているのに、変動するのはおかしいんじゃ?という指摘はごもっともです。今回は単なる思考実験と思ってください。
NOTE: これはあくまで真の値を知っているときの話であって、標本値の話ではない
::p_load(pwr, tidyverse)
pacman
<- function(n_control, n_exposed, p_event_control, rr_min = 0.25, rr_max=3.0){
PlotPower_byRR
# あるリスク比を定めると、powerを返す関数
<- function(risk_ratio){
GetPower_byRR<- pwr.2p2n.test(h = ES.h(p1 = p_event_control, p2 = p_event_control*risk_ratio),
res n1 = n_control,
n2 = n_exposed,
sig.level = 0.05,
alternative = "two.sided")
<- res[["power"]]
power return(power)
}
# イベント発生人数がN of participantsを超えるとエラーになるので、先に宣言しておく
<- ifelse(p_event_control*rr_max >= 1, 1/p_event_control, rr_max)
rr_max
<- seq(from=rr_min, to=rr_max, by=0.01)
scale_riskratio <- sapply(scale_riskratio, GetPower_byRR)
estimate_power
<- data.frame(risk_ratio = scale_riskratio, power = estimate_power)
df # RR < 1 でpower >= 0.8となる、1に近い (最大の) RRを得る
<- df %>%
df_rr1 filter(risk_ratio < 1 & power >= 0.8) %>%
arrange(power) # powerで昇順ソート
<- max(df_rr1$risk_ratio)
power_080_1
# RR > 1 でpower >= 0.8となる、1に近い (最小の) RRを得る
<- df %>%
df_rr2 filter(risk_ratio > 1 & power >= 0.80) %>%
arrange(power) # powerで昇順ソート
<- min(df_rr2$risk_ratio)
power_080_2
# description
<- sprintf("number of participants: control group=%d", n_control)
cha1 <- sprintf(", exposure group=%d\n", n_exposed)
cha2 <- sprintf("true value of event probability in control group=%.2f", p_event_control)
cha3 <- sprintf("blue hashed line: the maximum value of risk ratio (within RR <1) that achieved power ≥ 0.8=%.2f", power_080_1)
cha4 <- sprintf("\norange hashed line: the minimum value of risk ratio (within RR>1) that achieved power ≥ 0.8=%.2f", power_080_2)
cha5
= paste0(cha1, cha2, cha3)
subtitle = paste0(cha4, cha5)
caption
# plot
<- ggplot(data = df, aes(x = risk_ratio, y = power)) +
plot geom_line() +
geom_vline(xintercept = 1, colour = "darkgray") +
geom_vline(xintercept = power_080_1, linetype = 2, colour = "blue", alpha=0.8) +
geom_vline(xintercept = power_080_2, linetype = 2, colour = "orange", alpha=0.8) +
geom_hline(yintercept = 0.8, colour = "navy", alpha = 0.5) +
scale_y_continuous(breaks = seq(0, 1, 0.2)) +
labs(title = "Relationship between risk ratio and power in binary-outcome studies",
subtitle = subtitle,
caption = caption) +
xlab("risk ratio of exposed group compared to control group") +
theme_bw()
return(plot)
}
関数の説明
引数は次の通り
- n_control: コントロール群の人数
- n_exposed: 曝露群の人数
- p_event_control: コントロール群でのイベント発生割合
これらを入力すると、曝露のリスク比(横軸)に対するpower(縦軸)を返します。
example1
以降のセクションでは、リスク比 (RR) が1以上と考えます。(RR<1でも同じ議論です)
コントロール群100人、曝露群100人で、曝露群でのイベント発生割合が25%とします。
真のRRが1.75ならpowerは0.80となり、「十分」と考えられます。 ただし、リスク比が1.5ならpower=0.50程度となります。かなりばらつくんですね。
PlotPower_byRR(n_control = 100,
n_exposed = 100,
p_event_control = 0.25)
example2
人数を増やしてみましょう。今度はコントロール群200人、曝露グループ200人にします。
この場合、RR=1.75のときpowerはほぼ1 (100%) となります。人数が増えたので、当然です。 power=0.8を達成するリスク比は1.52となりました。
PlotPower_byRR(n_control = 200,
n_exposed = 200,
p_event_control = 0.25)
感想
先行研究で、RR=1.75 [95%CI: 1.50-2.00] みたいな結果があったとしましょう。 同じような研究を実施する場合、この値を使ってpower計算することになると思います。
素直にRR=1.75という点推定値を使えば、example1の通り、各群100人合計200人でokです。 ただし、「RR=1.75が真の値である」という仮定を置いているだけで、実際には下振れしてしまうかもしれません。期待値的に点推定値を使うのはご尤もなんですが、真の値なんて知り得ない以上、ある程度ばらつきや分布を考えてもいいのかも?と思ってしまいました。例えば ±1σ の幅を持たせてあげるとか。
こういう話は研究のリソースや研究倫理も絡むのでもっと難しい議論になりそうですね。ひとまず勉強の感想でした。