2×2の分割表について,確率の差・確率の比・オッズ比
前置き
2×2の分割表の確率の差,比,オッズ比のワルド検定およびワルド信頼区間についてまとめる.統計モデリングの勉強と接続しやすいよう,仮定している確率モデルを明示することを意識した.
モデルと点推定量
説明変数
この式は確率変数
とすると,次のような2×2の分割表が作れる.
| 成功 | 失敗 | 横合計 | |
|---|---|---|---|
このノートではこのような2×2の分割表について, (M) のモデルを通じて,仮説検定と区間推定を考えていく.
(M) のモデルでは
である.
である.最尤推定量は変数変換に対して不変なので,これを変換して推定量を導くことができる.
最初に一番簡単そうな恒等関数,すなわち
である.最尤推定量
を得る.ここからさらに,
が得られる.
次に,
である.最尤推定量
を得る.ここからさらに,
が得られる.
最後に,
である.最尤推定量
および,
が得られる.
「成功」と「失敗」の比,
まとめると次の表のようになる.
| 指標 | モデルの |
モデルのリンク関数 |
|---|---|---|
| 確率の差 | 恒等関数 | 恒等関数 |
| 確率の比 | 指数関数 | 対数関数 |
| オッズ比 | 逆ロジット関数 | ロジット関数 |
ここでリンク関数という言葉を導入した.一般化線形モデル(GLM; generalized linear model)の文脈では上の
次に知りたいのは
準備:デルタ法
このパートではベルヌーイ分布に従う
いま,ベルヌーイ分布を考えていたので
である.中心極限定理より次が成り立つ.
ここで
適当な関数の
を利用する.
両辺の平均を取ると,
分散を取ると,
である.中心極限定理より次が成り立つ.
この近似を利用することをデルタ法(delta method)と呼ぶ.
要するに,これを使って
特に
また
推定量の平均と分散
ワルド(Wald)検定では検定統計量
ここで
これよりワルド検定を利用するため,推定量の分散を求めていく.
まず
しかし
次に
である.
最後に
である.
ちなみにこの
Rによる実装例
下記のように実装した.上で求めた式をそのまま打ち込んだ,という感じでそんなに工夫したポイントはない.
CI_wald = function(effect, se, level){
alpha = (1-level)*0.5
z = qnorm(1-alpha, 0, 1)
lower = effect - se*z
upper = effect + se*z
return( unname(c(lower, upper)) )
}
pvalue_wald = function(effect0, effect, se){
pvfun = fucntion(v){pchisq(((effect-v)/se)^2, df=1, lower.tail = FALSE)}
return( sapply(effect0, pvfun) )
}
#差
RD = function(X){
x = X[,1]
n = rowSums(X)
phat = x/n
delta = unname(phat[1] - phat[2])
se = sqrt(sum(phat*(1-phat)/n))
return( list(estimates = delta, SE = se) )
}
#比
RR = function(X){
x = X[,1]
n = rowSums(X)
phat = x/n
beta = unname(log(phat[1]) - log(phat[2]))
se = sqrt(sum(1/x)-sum(1/n))
return( list(estimates=beta, SE = se) )
}
#オッズ比
OR = function(X,level=0.95, confint=TRUE){
tau = unname(log(X[1,1]/X[1,2]) - log(X[2,1]/X[2,2]))
se <- sqrt(sum(1/X))
return( list(estimates=tau, SE = se) )
}
データを 佐藤俊哉『宇宙怪人しまりす統計より重要なことを学ぶ』(朝倉書店) の4話でしまりす君がやったサブグループ解析から引用させてもらう.
library(dplyr)
library(ggplot2)
library(knitr)
lname = list("ヨクナール" = c("使用","未使用"),
"回復" = c("回復","未回復"),
"重症度"= c("重症","軽症"))
dat = array(c(40,20,20,20,
18,42,2,18), dim=c(2,2,2), dimnames = lname)
# サブグループ解析(しまりす君が層別解析と間違えてやったもの)
res_rd = apply(dat, 3, RD)
res_rr = apply(dat, 3, RR)
res_or = apply(dat, 3, OR)
tab_rd = t(sapply(res_rd,function(res){c(res$estimates, CI_wald(res$estimates, res$SE, 0.95))}))
tab_rr = t(sapply(res_rr,function(res){c(res$estimates, CI_wald(res$estimates, res$SE, 0.95))}))
tab_or = t(sapply(res_or,function(res){c(res$estimates, CI_wald(res$estimates, res$SE, 0.95))}))
#差(%)
t1 = data.frame(round(tab_rd*100, 1)) %>%
rename("点推定値"=X1,
"下限(95%信頼区間)"=X2,
"上限(95%信頼区間)"=X3) %>%
tibble::rownames_to_column("重症度")
print(t1)
writeLines(knitr::kable( t1 ), "kt1.txt")
#比
t2 = data.frame(round(exp(tab_rr), 2)) %>%
rename("点推定値"=X1,
"下限(95%信頼区間)"=X2,
"上限(95%信頼区間)"=X3) %>%
tibble::rownames_to_column("重症度")
print(t2)
writeLines(knitr::kable( t2 ), "kt2.txt")
#オッズ比
t3 = data.frame(round(exp(tab_or), 2)) %>%
rename("点推定値"=X1,
"下限(95%信頼区間)"=X2,
"上限(95%信頼区間)"=X3) %>%
tibble::rownames_to_column("重症度")
print(t3)
writeLines(knitr::kable( t3 ), "kt3.txt")
差(%):
| 重症度 | 点推定値 | 下限(95%信頼区間) | 上限(95%信頼区間) |
|---|---|---|---|
| 重症 | 16.7 | -2.9 | 36.2 |
| 軽症 | 20.0 | 2.5 | 37.5 |
比:
| 重症度 | 点推定値 | 下限(95%信頼区間) | 上限(95%信頼区間) |
|---|---|---|---|
| 重症 | 1.33 | 0.93 | 1.91 |
| 軽症 | 1.29 | 1.03 | 1.60 |
オッズ比:
| 重症度 | 点推定値 | 下限(95%信頼区間) | 上限(95%信頼区間) |
|---|---|---|---|
| 重症 | 2.00 | 0.88 | 4.54 |
| 軽症 | 3.86 | 0.81 | 18.39 |
テキストと同じ結果が得られた.
ついで,glm の出力とも比べてみる.
dat_c = dat[,,1]
x = c(1, 0)
fit_iden = glm(dat_c~x, family = binomial("identity"))
s_iden = summary(fit_iden)
kable(s_iden$coefficients)
kable( c(simplify2array(res_rd[[1]]), Pvalue = pvalue_wald(0, res_rd[[1]]$estimates, res_rd[[1]]$SE)) )
fit_log = glm(dat_c~x, family = binomial("log"))
s_log = summary(fit_log)
kable(s_log$coefficients)
kable( c(simplify2array(res_rr[[1]]), Pvalue = pvalue_wald(0, res_rr[[1]]$estimates, res_rr[[1]]$SE)) )
fit_logis = glm(dat_c~x, family = binomial("logit"))
s_logis = summary(fit_logis)
kable(s_logis$coefficients)
kable( c(simplify2array(res_or[[1]]), Pvalue = pvalue_wald(0, res_or[[1]]$estimates, res_or[[1]]$SE)) )
恒等リンクと確率の差:
| Estimate | Std. Error | z value | Pr(>|z|) | |
|---|---|---|---|---|
| (Intercept) | 0.5000000 | 0.0790569 | 6.324555 | 0.0000000 |
| x | 0.1666667 | 0.0997682 | 1.670538 | 0.0948129 |
| x | |
|---|---|
| estimates | 0.1666667 |
| SE | 0.0997682 |
| Pvalue | 0.0948129 |
対数リンクと確率の比:
| Estimate | Std. Error | z value | Pr(>|z|) | |
|---|---|---|---|---|
| (Intercept) | -0.6931472 | 0.1581139 | -4.383848 | 0.0000117 |
| x | 0.2876821 | 0.1825742 | 1.575700 | 0.1150950 |
| x | |
|---|---|
| estimates | 0.2876821 |
| SE | 0.1825742 |
| Pvalue | 0.1150950 |
ロジットリンクとオッズ比:
| Estimate | Std. Error | z value | Pr(>|z|) | |
|---|---|---|---|---|
| (Intercept) | 0.0000000 | 0.3162278 | 0.000000 | 1.0000000 |
| x | 0.6931472 | 0.4183300 | 1.656939 | 0.0975319 |
| x | |
|---|---|
| estimates | 0.6931472 |
| SE | 0.4183300 |
| Pvalue | 0.0975319 |
同じ結果が得られる.
あとがき
もともとやりたかったのは実装例のサブグループ解析( 佐藤俊哉『宇宙怪人しまりす統計より重要なことを学ぶ』(朝倉書店) )の再現で,しかもこのサブグループ解析は層別解析(層化統合解析)と間違えやすいものの例としてでてくるので,この記事の内容は本題の準備の準備くらいにあたる.
一方で,2×2の分割表についてのこれらの指標(差,比,オッズ比)自体は広く使われるものなので,この記事は『宇宙怪人しまりす統計より重要なことを学ぶ』と独立に読んでも意味のある内容になっていると思う.
また,ここでは勉強のため自作の関数を定義したが,2×2の表,オッズ比,相対危険度 - 奥村晴彦 で複数のパッケージが比較・紹介されている.
Discussion