2×2の表,オッズ比,相対危険度

オッズ比,相対危険度

疫学では次のような2×2(2行2列)の表を考えることがよくあります:

疾病あり疾病なし
曝露あり$a$$b$
曝露なし$c$$d$

「曝露」(ばくろ,exposure)とは,何らかの条件にさらされることです(必ずしも害になるものとは限りません)。「疾病」(しっぺい,disease)は病気のことですが,より一般に「結果」(outcome)というほうがいいかもしれません。具体的には

肺がんあり肺がんなし
喫煙あり$a$$b$
喫煙なし$c$$d$

のようなことを考えればいいでしょう。

このとき,$a/(a+b)$ や $c/(c+d)$ をそれぞれの場合の危険度(risk)といい,その比 $\dfrac{a/(a+b)}{c/(c+d)}$ を相対危険度(相対リスク,relative risk,RR)といいます。

また,$a/b$ や $c/d$ をそれぞれの場合のオッズ(odds)といい,その比 $\dfrac{a/b}{c/d}$ をオッズ比(odds ratio,OR)といいます。

危険度とオッズは,小さい値のときはどちらもほぼ等しくなります。

相対危険度は,行・列のどちらを原因・結果と考えるかによって,答えが違ってきます(数学的には,行列の転置をとると,答えが違ってきます)。これに対して,オッズ比は行と列を入れ替えても変わりません。

オッズ比の対数 $\log \mathrm{OR} = \log a - \log b - \log c + \log d$ は正規分布で近似でき,その分散は,各度数をポアソン分布とすれば $V(\log a) \approx 1/a$ などが成り立つので,$V(\log \mathrm{OR}) \approx 1/a + 1/b + 1/c + 1/d$ と近似できます。相対危険度も対数をとって $V(\log \mathrm{RR}) \approx 1/a - 1/(a+b) + 1/c - 1/(c+d)$ で近似します。

オッズ比や相対危険度の信頼区間が 1 を含むことと,行・列が独立であること($a:b = c:d$)とは,数学的に同じことですが,信頼区間を求める方法や,独立性の検定の方法によって,結果が一致しないことがあります(「検定」とはそんなもので,$p = 0.04$ と $p = 0.06$ の違いは実質科学的なものではなく,単なる線引きの問題です)。

オッズ比と相対危険度には

\[ \mathrm{RR} = \frac{\mathrm{OR}(1 + c/d)}{1 + (c/d)\mathrm{OR}} = \frac{\mathrm{OR}}{1 - c/(c+d) + (c/(c+d))\mathrm{OR}} \]

という関係があり,比較的安定に求められる被曝露群のオッズ $c/d$ または危険度 $c/(c+d)$ を使った式で変換できます。

これら以外に,リスク差(risk difference,RD)$a/(a+b) - c/(c+d)$ も使われます。この分散は2項分布近似で $V(\mathrm{RD}) \approx ab/(a+b)^3 + cd/(c+d)^3$ となります。

このページの最後に,ファイ係数,クラメールの $V$,Yule の $Q$ についても付記しました。

対応がある場合の2×2の表についてはMcNemar検定をご覧ください。

Rによる2×2の表の表し方

次のような表があったとします(この論文の表IIの男性の一部):

肺がんあり肺がんなし
喫煙あり23123036
喫煙なし2610813

この表を縦に読んでいくと,次のようになります:

c(231, 26, 23036, 10813)
[1]   231    26 23036 10813

これを2行2列の行列の形にするには,次のように行数(nrow),列数(ncol)のどちらかを指定します:

matrix(c(231,26,23036,10813), nrow=2)
     [,1]  [,2]
[1,]  231 23036
[2,]   26 10813

数値を横に(行ごとに)読んでいった場合は,次のように byrow=TRUE というオプションを与えます:

matrix(c(231,23036,26,10813), nrow=2, byrow=TRUE)
     [,1]  [,2]
[1,]  231 23036
[2,]   26 10813

変数に代入しましょう:

x = matrix(c(231,26,23036,10813), nrow=2)
x
     [,1]  [,2]
[1,]  231 23036
[2,]   26 10813

行・列に名前を付けるには次のようにします:

rownames(x) = c("喫煙","非喫煙")
colnames(x) = c("肺がんあり","肺がんなし")
x
       肺がんあり 肺がんなし
喫煙          231      23036
非喫煙         26      10813

相対危険度やオッズ比の求め方

手計算と照合しやすいように,数値例を簡単なものに変えました。以下では次のデータについて計算しています:

x = matrix(c(12,5,6,12), nrow=2)
x
     [,1] [,2]
[1,]   12    6
[2,]    5   12

手計算

オッズ比は 4.8,その対数(1.5686)の分散は 0.5333,正規分布近似の $p$ 値は 0.0317,95%信頼区間は [1.147127, 20.084960] になります:

(x[1,1]/x[1,2]) / (x[2,1]/x[2,2])
[1] 4.8
log((x[1,1]/x[1,2]) / (x[2,1]/x[2,2]))
[1] 1.568616
1/x[1,1] + 1/x[1,2] + 1/x[2,1] + 1/x[2,2]
[1] 0.5333333
pnorm(-1.568616 / sqrt(0.5333333)) * 2
[1] 0.03172043
exp(1.568616 + qnorm(c(0.025,0.975)) * sqrt(0.5333333))
[1]  1.147127 20.084960

Fisherの正確検定による方法

関数 fisher.test() を使ってもオッズ比とその信頼区間が求められますが,上で定義したオッズ比とは少し違った定義(周辺分布を固定したときの最尤推定量,conditional MLE)を使っています。詳しくはFisherの正確検定をご覧ください。

fisher.test(x)

	Fisher's Exact Test for Count Data

data:  x
p-value = 0.04371
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  0.9465292 25.7201471
sample estimates:
odds ratio 
  4.568253 

オッズ比はさきほどの 4.8 ではなく,4.568253 となりました。これは定義が微妙に違うためです。詳しくはFisherの正確検定をご参照ください。また,95%信頼区間は $[0.95, 25.72]$ で,1 を含んでいるので有意でないように見えますが,$p$ 値は 0.05 未満です。

カイ2乗検定による方法

これはオッズ比などを求めるものではありませんが,行・列の独立性の検定をします。デフォルトでは連続性の補正をします。

chisq.test(x) # 補正あり

	Pearson's Chi-squared test with Yates' continuity correction

data:  x
X-squared = 3.4808, df = 1, p-value = 0.06208

chisq.test(x, correct=FALSE) # 補正なし

	Pearson's Chi-squared test

data:  x
X-squared = 4.8577, df = 1, p-value = 0.02752

補正あり・なしで $p$ 値はそれぞれ 0.06208,0.02752 です。

Epiパッケージによる方法

Epiパッケージで2×2の表を扱う関数は twoby2() です。いろいろ出力しますが,オッズ比は通常の定義(unconditional MLE)を使い,信頼区間はWaldの方法(正規分布による近似)で求めています。

install.packages("Epi")  # 初めての場合はパッケージをインストールする
library(Epi)             # ライブラリとして読み込む
twoby2(x)
2 by 2 table analysis: 
------------------------------------------------------ 
Outcome   : Col 1 
Comparing : Row 1 vs. Row 2 

      Col 1 Col 2    P(Col 1) 95% conf. interval
Row 1    12     6      0.6667    0.4288   0.8420
Row 2     5    12      0.2941    0.1280   0.5419

                                   95% conf. interval
             Relative Risk: 2.2667    1.0128   5.0730
         Sample Odds Ratio: 4.8000    1.1471  20.0850
Conditional MLE Odds Ratio: 4.5683    0.9465  25.7201
    Probability difference: 0.3725    0.0427   0.6073

             Exact P-value: 0.0437 
        Asymptotic P-value: 0.0317 
------------------------------------------------------

相対リスクは 2.2667 で,95%信頼区間は $[1,01, 5.07]$ です。また,標本オッズ比は 4.8 で,95%信頼区間は $[1.15, 20.09]$ です。その下の Conditional MLE Odds Ratio は fisher.test() の出してくる値です。$p$ 値は Exact のほうは fisher.test() と同じ 0.0437 で,Asymptotic のほうは近似です。数が多い場合は Asymptotic だけの表示になり,場合によっては「0」と表示されることがありますが,その場合は「$p < 0.001$ で有意」と報告すればいいでしょう(丸める前の値を知りたければ twoby2(x)$p.value と打ち込みます)。

epitoolsパッケージによる方法

epitoolsパッケージには4つの方法が用意されています:

上のEpiパッケージの twoby2() のオッズ比と同じ結果を出すのは oddsratio.wald() です。オッズ比とその信頼区間は $measure の Exposed2 欄に出力されます:

install.packages("epitools")  # 初めての場合はパッケージをインストールする
library(epitools)             # ライブラリとして読み込む
oddsratio.wald(x)
$data
          Outcome
Predictor  Disease1 Disease2 Total
  Exposed1       12        6    18
  Exposed2        5       12    17
  Total          17       18    35

$measure
          odds ratio with 95% C.I.
Predictor  estimate    lower    upper
  Exposed1      1.0       NA       NA
  Exposed2      4.8 1.147127 20.08496

$p.value
          two-sided
Predictor  midp.exact fisher.exact chi.square
  Exposed1         NA           NA         NA
  Exposed2 0.03527143   0.04371017 0.02752225

$correction
[1] FALSE

attr(,"method")
[1] "Unconditional MLE & normal approximation (Wald) CI"

ほかの方法もまとめて,違うところだけ記します:

oddsratio.wald(x)
  Exposed2      4.8 1.147127 20.08496
oddsratio.midp(x)
  Exposed2 4.503795 1.105796 21.10137
oddsratio.fisher(x)
  Exposed2 4.568253 0.9465292 25.72015
oddsratio.small(x)
  Exposed2 3.428571 1.099686 17.37077

vcdパッケージによる方法

install.packages("vcd")
library(vcd)
oddsratio(x, log=FALSE)
[1] 4.8

Waldの方法が使われます。単純明快にオッズ比(unconditional)だけ出力されます。信頼区間や $p$ 値は次のようにします:

confint(oddsratio(x, log=FALSE))
          lwr      upr
[1,] 1.147127 20.08496
summary(oddsratio(x))
     Log Odds Ratio Std. Error z value Pr(>|z|)  
[1,]         1.5686     0.7303  2.1479  0.03172 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

fmsbパッケージによる方法

中澤 港 先生のfmsbパッケージにもepitoolsと同じ名前の oddsratio()rateratio()riskratio() という関数があります。

この oddsratio() は,行列の指定と同様,縦順に数値を4つ並べます。

install.packages("fmsb")
library(fmsb)
oddsratio(12, 5, 6, 12)
           Disease Nondisease Total
Exposed         12          6    18
Nonexposed       5         12    17
Total           17         18    35

	Odds ratio estimate and its significance probability

data:  12 5 6 12
p-value = 0.02983
95 percent confidence interval:
  1.147127 20.084959
sample estimates:
[1] 4.8

Waldの方法を使っています。詳細は中澤先生の鵯記878をご覧ください。

exact2x2パッケージによる方法

exact2x2についてはFisherの正確検定にも少し書きました。このパッケージは exact2x2() という関数を定義していますが,特によく使うオプションについては fisher.exact()blaker.exact()mcnemar.exact() という名前でもアクセスできます。

install.packages("exact2x2")
library(exact2x2)
fisher.exact(x)

	Two-sided Fisher's Exact Test (usual method using minimum likelihood)

data:  x
p-value = 0.04371
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  1.0905 22.9610
sample estimates:
odds ratio 
  4.568253 

blaker.exact(x)

	Blaker's Exact Test

data:  x
p-value = 0.04371
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  1.0905 23.6488
sample estimates:
odds ratio 
  4.568253 

fisher.exact() の $p$ 値とオッズ比の点推定値(conditional)は fisher.test() と同じですが,信頼区間は $p$ 値と同じ方法で求めていますので,片方だけ有意ということがありません。

まとめると次のようになります:

パッケージ関数p値オッズ比95%信頼区間
-手計算0.031720434.8[1.147127, 20.084960]
-fisher.test()0.043714.568253[0.9465292, 25.7201471]
-chisq.test()0.06208--
-chisq.test(correct=FALSE)0.02752--
Epitwoby2()Exact: 0.0437Sample: 4.8000Sample: [1.1471, 20.0850]
Epitwoby2()Asymptotic: 0.0317Conditional: 4.5683Conditional: [0.9465, 25.7201]
epitoolsoddsratio.wald()chisq: 0.027522254.8[1.147127, 20.08496]
epitoolsoddsratio.midp()0.035271434.503795[1.105796, 21.10137]
epitoolsoddsratio.fisher()0.043710174.568253[0.9465292, 25.72015]
epitoolsoddsratio.small()-3.428571[1.099686, 17.37077]
vcdoddsratio()0.031724.8[1.147127, 20.08496]
fmsboddsratio()0.029834.8[1.147127, 20.084959]
exact2x2fisher.exact()0.043714.568253[1.0905, 22.9610]
exact2x2blaker.exact()0.043714.568253[1.0905, 23.6488]

(付)glmパッケージによる方法

行列ではなく生データが次のように与えられている場合の方法です。logistic.display() はepiDisplay(旧epicalc)パッケージの関数です。

x = rep(0:1, c(18,17))
y = rep(c(0,1,0,1), c(12,6,5,12))
r = glm(y ~ x, family="binomial")
logistic.display(r)

Logistic regression predicting y 
 
           OR(95%CI)         P(Wald's test) P(LR-test)
x: 1 vs 0  4.8 (1.15,20.08)  0.032          0.026     
                                                      
Log-likelihood = -21.7558
No. of observations = 35
AIC value = 47.5116

津田敏秀先生の「有病オッズ比」問題に計算例があります。

相対危険度の信頼区間の求め方のいろいろについては,R help - [R] Confidence interval for relative risk という議論のMichael Deweyによるまとめ http://www.zen103156.zen.co.uk/rr.pdf や,Calculation of Relative Risk Confidence Interval - Cross Validated の議論をご覧ください。

(付)ファイ係数,クラメールのVなど

$2 \times 2$ に限らず,表の各行(各列)の独立性を検定するためによく使われるのが「カイ2乗」($\chi^2$)という統計量です(カイ2乗検定参照)。これを0以上1以下に収まるように変換したものが「クラメールの $V$」(Cramér's $V$)です:

\[ V = \sqrt{\frac{\chi^2}{n \cdot \mathrm{min}(\mathrm{nrow}-1,\mathrm{ncol}-1)}} \]

ここで $n$ は表の値を全部合計したもの,nrow と ncol は行数,列数です。特に $2 \times 2$ の表については,ファイ係数(phi coefficient,$\phi$)と呼ばれます:

\[ \phi = \sqrt{\frac{\chi^2}{n}} = \frac{|ad-bc|}{\sqrt{(a+b)(c+d)(a+c)(b+d)}} \]

この分子の絶対値を外せば,どちらの向きに関連があるかもわかります。以下では絶対値なしのほうを使います。

2通りの定義でさきほどの行列 x のファイ係数を求めてみましょう:

sqrt(chisq.test(x,correct=FALSE)$statistic / sum(x))
 X-squared 
0.04054061
a = x[1,1]; b = x[1,2]; c = x[2,1]; d = x[2,2]
(a*d-b*c) / sqrt((a+b)*(c+d)*(a+c)*(b+d))
[1] 0.04054061

ライブラリ psych にファイ係数(絶対値なし)を求める関数があります:

install.packages("psych")
library(psych)
phi(x)
[1] 0.04
phi(x, digits=8)
[1] 0.04054061

ファイ係数と似たものに Yule の $Q$ があります。これはオッズ比(OR)を -1 から 1 までの範囲に変換したものとも考えられます:

\[ Q = \frac{ad-bc}{ad+bc} = \frac{\mathrm{OR} - 1}{\mathrm{OR} + 1} \]

これは psych パッケージの Yule() で計算できます:

Yule(x)
[1] 0.6131828
(a*d-b*c) / (a*d+b*c)
[1] 0.6131828

これらの比較は次の論文をご覧ください:

どれを使うかは分野によると思いますが,医学・疫学方面では相対危険度(RR)やオッズ比(OR)(いずれも対数変換したもの)がよく用いられます(メタアナリシス参照)。What is the difference between odds ratio and relative risk? という議論も参考になります。

どの効果量を使うかで迷ったら,オッズ比を使えばいいでしょう。Michael Borenstein ほか Introduction to Meta-Analysis (Wiley, 2009) はオッズ比について次のように書いています:

Many people find this effect size measure less intuitive than the risk ratio, but the odds ratio has statistical properties that often make it the best choice for a meta-analysis.

$2 \times 2$ より大きい表の「効果量」はクラメールの $V$ でいいか,という話がありますが,まずは効果量の考え方に立ち戻ってデータの扱い方を考え直したほうがいいでしょう。

連続量を大小または大中小に分けて $2 \times 2$ や $2 \times 3$ の表にした場合は,確実に元の連続量に立ち戻るほうがいいでしょう。$n$ 段階の順序尺度の量は 1, 2, …, $n$ の得点に直すほうがいいでしょう。