多重比較補正 完全ガイド — Bonferroni・Holm・Benjamini-Hochberg(FDR)

ある新薬の臨床試験で、20種類の症状について「薬を飲んだ群と飲まない群で差があるか」を一つひとつ検定したとします。20回のうち1回、ある症状で「有意差あり(p < 0.05)」という結果が出ました。研究者は喜びますが、ここで立ち止まって考えてみてください。たとえ薬がまったく効いていなくても、20回検定すれば、そのうち1回くらいは偶然「有意」になってしまうのではないか——。

実際、その直感は正しいのです。1回の検定で偽陽性(本当は差がないのに「差あり」と判定する誤り)が起きる確率を5%に抑えても、検定を20回繰り返せば、少なくとも1回偽陽性が出る確率は約64%にまで跳ね上がります。これが多重比較問題(multiple comparisons problem)です。検定の回数が増えるほど「偶然の有意」が紛れ込み、放っておくと結論はゴミだらけになります。

この問題は、現代のデータ解析のあらゆる場面で顔を出します。たとえば遺伝子発現解析では、2万個もの遺伝子について一斉に「病気と関連するか」を検定します。何も補正しなければ、関連のない遺伝子が数百個も「有意」と誤判定されてしまう。あるいはWebサービスのA/Bテストで、ボタンの色・配置・文言…と多数の指標を同時に比べると、どれかが偶然「勝った」ように見えてしまう。脳画像解析(fMRI)では数万のボクセル(脳の小区画)それぞれで検定するため、補正なしでは「死んだ鮭の脳が画像に反応した」という有名なパロディ研究すら成立してしまいます。

本記事では、この多重比較問題に立ち向かう代表的な補正法を、直感・数理・実装の3点セットで解き明かします。

本記事の内容

  • 多重比較問題の正体と、FWER $=1-(1-\alpha)^m$ の導出
  • 抑えるべき誤りの2つの定義 —— FWER(家族単位誤り率)と FDR(偽発見率)の違い
  • Bonferroni 補正・Šidák 補正・Holm 逐次法・Benjamini-Hochberg(FDR) の数理と証明の要点
  • 検出力(power)の観点からの使い分けと、手法選択のフローチャート
  • statsmodels.stats.multitest.multipletests を使った Python 実装と、検出力・偽陽性数のシミュレーション
  • 遺伝子発現解析・A/Bテスト・脳画像への応用と、p値ハッキングとの関係

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

直感:20回検定すれば1回は偶然有意になる

まず、なぜ検定を繰り返すと危険なのかを、感覚として掴んでおきましょう。

仮説検定では、帰無仮説(「差はない」)が正しいときに誤ってそれを棄却してしまう確率を有意水準 $\alpha$(ふつう 0.05)に設定します。つまり、本当は差がない状況で「差あり」と叫んでしまう誤り(第一種過誤、偽陽性)の確率を 5% に抑えるのが1回の検定の約束事です。

ところが「5% の確率で起こる誤り」も、何度も繰り返せば話が変わります。サイコロを1回振って6が出る確率は1/6ですが、6回振れば「少なくとも1回は6が出る」確率はずっと高くなります。検定も同じです。1回ごとに 5% の偽陽性リスクがあるなら、何十回も検定を繰り返せば「どこかで偽陽性が出る」のはむしろ当たり前なのです。

20回の検定のうち1個が偶然有意になる多重比較問題の概念図

上の図は、20個の検定すべてで「本当は差がない(帰無仮説が真)」という状況を表しています。それでも各検定が 5% の確率で誤検出するため、20個のうち1個(この例では検定8)が偶然「有意!」になっています。一つひとつの検定は正しく 5% に制御されているのに、全体として見ると「少なくとも1個は偽陽性」という事態が約64%の確率で起きてしまう——これが多重比較問題の本質です。個々の検定が悪いのではなく、たくさん検定することそのものが偽陽性を生むのです。

では、この「少なくとも1個が偽陽性になる確率」は、検定回数に応じてどう増えていくのでしょうか。次に数式で正確に追いかけます。

多重比較問題の数理

偽陽性が1個も出ない確率

$m$ 個の検定を行い、それらがすべて独立で、かつすべての帰無仮説が真(本当は差がない)だとします。各検定の有意水準を $\alpha$ とすると、1つの検定で「正しく棄却しない(偽陽性を出さない)」確率は $1 – \alpha$ です。

$m$ 個の検定が独立なら、「$m$ 個すべてで偽陽性を出さない」確率は、それぞれの確率の積になります。

$$ P(\text{偽陽性ゼロ}) = (1 – \alpha)^m $$

ここで独立性を使いました。独立な事象がすべて起こる確率は、各確率の掛け算になるからです。

Family-Wise Error Rate(FWER)

私たちが恐れているのは「偽陽性ゼロ」の反対、すなわち「少なくとも1個は偽陽性が出る」事態です。余事象を取れば、

$$ \mathrm{FWER} = P(\text{少なくとも1個の偽陽性}) = 1 – (1 – \alpha)^m $$

が得られます。この量を Family-Wise Error Rate(FWER、家族単位誤り率) と呼びます。「家族(family)」とは、ひとまとまりに扱う検定の集合のことです。FWER は「その家族の中で1個でも偽陽性を出してしまう確率」を表します。

具体的な数値を入れてみましょう。$\alpha = 0.05$ のとき、

$$ \mathrm{FWER} = 1 – 0.95^m $$

となります。$m = 5$ なら $1 – 0.95^5 \approx 0.23$、$m = 20$ なら $1 – 0.95^{20} \approx 0.64$、$m = 50$ なら $1 – 0.95^{50} \approx 0.92$ です。検定が50個もあれば、補正なしでは9割以上の確率でどこかに偽陽性が紛れ込む計算になります。

検定回数mに対するFWERの増加曲線

この図は、検定回数 $m$ に対する FWER の増加を示しています。青い実線($\alpha=0.05$)は急峻に立ち上がり、$m=20$ で早くも 0.64 に達します。緑の破線($\alpha=0.01$)はもっと緩やかですが、それでも $m$ が大きくなれば確実に上昇していきます。赤い点線は、補正によって FWER を 0.05 に抑え込んだ理想の上限です。多重比較補正の目標は、まさにこの青い曲線を赤い点線まで「押し下げる」ことに他なりません。

不等式による上界(独立でなくても成り立つ)

実際の検定は独立とは限りません(同じデータを使い回せば相関します)。独立性を仮定しない場合でも使える、便利な上界があります。$A_i$ を「$i$ 番目の検定で偽陽性が出る」事象とすると、和事象の確率は個々の確率の和を超えないというブールの不等式(Bonferroniの不等式)が成り立ちます。

$$ \mathrm{FWER} = P\!\left(\bigcup_{i=1}^{m} A_i\right) \leq \sum_{i=1}^{m} P(A_i) = m\alpha $$

最初の不等号がブールの不等式です。和集合の確率は、たとえ事象が重なり合っていても、各確率の単純な和で上から押さえられます。これは独立性を一切仮定しないので、相関のある検定にもそのまま使えます。この $\mathrm{FWER} \leq m\alpha$ という素朴な上界が、次章以降の Bonferroni 補正の理論的な根拠になります。

ここまでで「補正なしでは FWER が制御不能に増える」ことがわかりました。では、そもそも何を抑えれば「補正できた」と言えるのでしょうか。実は、抑えるべき誤りの定義には大きく2つの流儀があります。

FWER と FDR:抑える誤りの2つの定義

多重比較補正の世界には、目標の異なる2つの大きな流派があります。一つは前章で見た FWER(家族単位誤り率)、もう一つが FDR(False Discovery Rate、偽発見率) です。両者の違いを理解することが、手法選択の出発点になります。

検定結果の分類

$m$ 個の検定を行った結果を、真実(帰無が真か偽か)と判定(棄却したか否か)で分類すると、次の表のようになります。

$$ \begin{array}{c|cc|c} & \text{棄却しない} & \text{棄却した(発見)} & \text{合計} \\ \hline \text{帰無が真} & U & V & m_0 \\ \text{対立が真} & T & S & m_1 \\ \hline \text{合計} & m – R & R & m \end{array} $$

ここで $V$ は偽陽性(本当は差がないのに棄却した数)、$S$ は真陽性(正しく検出した数)、$R = V + S$ は棄却した(=「発見」した)総数です。私たちが減らしたいのは $V$ です。

FWER:1個でも偽陽性を出す確率

FWER は「偽陽性が1個以上ある確率」、すなわち

$$ \mathrm{FWER} = P(V \geq 1) $$

と定義されます。Bonferroni 法や Holm 法は、この FWER を $\alpha$ 以下に抑えることを目標にします。$V \geq 1$ を許さないという厳しい基準なので、「1個でも偽陽性を出したら致命的」な場面に向いています。

FDR:発見の中の偽陽性の「割合」

一方 FDR は、偽陽性の「個数」ではなく「割合」に注目します。発見した $R$ 個のうち、偽陽性 $V$ が占める割合の期待値です。

$$ \mathrm{FDR} = E\!\left[\frac{V}{R}\right] = E\!\left[\frac{V}{\max(R, 1)}\right] $$

右側の $\max(R,1)$ は、何も発見しなかった($R=0$)ときに $0/0$ となるのを避けるための約束です($R=0$ なら FDR への寄与は 0 とする)。FDR を $q$(たとえば 0.10)に抑えるとは、「発見したもののうち偽物は平均10%までに抑える」という意味です。1000個発見して100個が偽物でも許容する——FWER に比べてはるかに緩い基準です。

FWERとFDRの違いを示す概念対比図

この図は両者の哲学の違いを端的に表しています。左の FWER 制御では、棄却した6個すべてが真陽性で偽陽性ゼロ。「とにかく間違えたくない」という厳格さの代償に、検出できる数が少なくなります。右の FDR 制御では、20個発見してそのうち2個(FDR=10%)が偽陽性。少数の偽物を許す代わりに、ずっと多くの真の発見を拾えています。

どちらを使うべきか

選択の基準はシンプルです。1個の偽陽性が致命的なら FWER、たくさんの候補から見込みのあるものを絞り込みたいなら FDR です。新薬の最終承認判断のように「効かない薬を承認したら大事故」という場面では FWER。一方、2万遺伝子から「次に詳しく調べる価値のある数百個」を選びたい探索的な解析では、多少の偽物が混じっても FDR で広く拾う方が合理的です。

それでは、具体的な補正法を一つずつ見ていきましょう。まずは最もシンプルな Bonferroni 補正からです。

Bonferroni 補正:最もシンプルで最も保守的

考え方

前章のブールの不等式 $\mathrm{FWER} \leq m\alpha$ を思い出してください。$m$ 個の検定それぞれで有意水準 $\alpha$ を使うと FWER は最大 $m\alpha$ まで膨らみます。ならば話は逆で、各検定の有意水準を $m$ で割って小さくしてやれば、全体の FWER を $\alpha$ に抑え込めるはずです。

これが Bonferroni 補正 の発想です。各検定の閾値を

$$ \alpha_{\text{Bonf}} = \frac{\alpha}{m} $$

とし、p値が $\alpha/m$ より小さいときだけ棄却します。たとえば $m=20$ なら、各検定では $0.05/20 = 0.0025$ を閾値にする、というわけです。

FWER を抑えることの証明

本当に FWER $\leq \alpha$ になるのか、ブールの不等式で確認しましょう。各検定で閾値を $\alpha/m$ に設定すると、$i$ 番目の検定で偽陽性が出る確率は $P(A_i) = \alpha/m$ 以下です(帰無が真のとき)。すると、

$$ \mathrm{FWER} = P\!\left(\bigcup_{i=1}^{m} A_i\right) \leq \sum_{i=1}^{m} P(A_i) \leq \sum_{i=1}^{m} \frac{\alpha}{m} $$

となります。ここで最初の不等号にブールの不等式を、2番目の不等号に「各偽陽性確率は $\alpha/m$ 以下」を使いました。最後の和は $m$ 項の足し算なので、

$$ \sum_{i=1}^{m} \frac{\alpha}{m} = m \cdot \frac{\alpha}{m} = \alpha $$

と $\alpha$ に等しくなります。よって $\mathrm{FWER} \leq \alpha$ が示せました。ブールの不等式は独立性を使わないので、検定が互いに相関していても、この保証は崩れません。これが Bonferroni 補正の最大の強みです。

Bonferroni補正の閾値とp値の比較

この図は、$m=10$ 個の検定の p値を小さい順に並べ、無補正の閾値 0.05(青の破線)と Bonferroni 閾値 $0.05/10=0.005$(赤の実線)を引いたものです。緑のバーが「真に効果あり」、紫が「帰無が真」です。無補正なら 0.05 を下回る検定はすべて棄却してしまいますが、Bonferroni では赤線(0.005)を下回るごく一部(★印)しか棄却しません。閾値を一律に厳しくすることで、紫(帰無)が誤って棄却されるのを防いでいるのがわかります。

弱点:保守的すぎる

Bonferroni 補正は単純で安全ですが、保守的すぎるという欠点があります。$m$ が大きいと閾値 $\alpha/m$ が極端に小さくなり、本当に効果がある検定すら見逃しやすくなります。$m = 10{,}000$ なら閾値は $0.000005$ —— これを下回るのは至難の業で、真の発見まで潰してしまいます。つまり偽陽性を恐れるあまり、検出力(power、真の効果を検出する力)が大きく犠牲になるのです。

この保守性をやわらげる工夫として、まず「独立性を積極的に使う」Šidák 補正、そして「一律でなく段階的に閾値を緩める」Holm 法が考案されました。次に、Bonferroni を逐次的に改良した Holm 法を見ていきます。

Holm 逐次法:Bonferroni を改良した万能選手

考え方

Bonferroni はすべての検定に同じ厳しい閾値 $\alpha/m$ を課しました。しかし、最も小さい p値(最も有意らしい検定)にまで $\alpha/m$ という最厳の基準を課す必要は本当にあるでしょうか。Holm 法(Holm’s step-down method)は、p値を小さい順に並べ、順位に応じて閾値を段階的に緩めることで、FWER を守りつつ検出力を上げます。

手順

p値を小さい順にソートして $p_{(1)} \leq p_{(2)} \leq \cdots \leq p_{(m)}$ とします。$i$ 番目に小さい p値 $p_{(i)}$ に対する閾値を

$$ \alpha_{(i)} = \frac{\alpha}{m – i + 1} $$

とします。最も小さい $p_{(1)}$ には $\alpha/m$(Bonferroni と同じ最厳)、2番目の $p_{(2)}$ には $\alpha/(m-1)$、…と、順位が進むほど分母が小さくなって閾値が緩くなります。最後の $p_{(m)}$ にはそのまま $\alpha$ が課されます。

判定は逐次的(step-down)に行います。

  1. $p_{(1)} \leq \alpha/m$ なら棄却して次へ。そうでなければそこで停止し、以降はすべて棄却しない。
  2. $p_{(2)} \leq \alpha/(m-1)$ なら棄却して次へ。そうでなければ停止。
  3. 以下同様に、$p_{(i)} > \alpha/(m-i+1)$ となる最初の $i$ で止め、それ以降は棄却しない。

「一度でも閾値を超えたら、そこで打ち切る」のがポイントです。

Holm逐次法の階段状の閾値と停止位置

この図は、ソートした p値(点)と、Holm の閾値 $\alpha/(m-i+1)$(オレンジの階段)、Bonferroni の閾値 $\alpha/m$(赤の破線)を重ねたものです。Holm の閾値は順位 $i$ とともに右肩上がりに緩み、Bonferroni の一律の閾値より常に高い位置にあります。緑の点が棄却された検定で、紫の点が棄却されなかったもの。閾値を超えた地点(点線)で判定が打ち切られているのが見て取れます。Bonferroni より閾値が緩い分、より多くの真の効果を拾えるのです。

Holm が FWER を守る理由

Holm 法も FWER $\leq \alpha$ を保証します。直感的な根拠を述べます。仮に偽陽性が起き始めるとすれば、それは最も小さい閾値 $\alpha/m$ を最初の真の帰無仮説が突破するときです。真の帰無仮説が $m_0$ 個あるとき、それらの中で最小の p値が $\alpha/m \leq \alpha/m_0$ を下回る確率は、ブールの不等式から $m_0 \cdot \alpha/m \leq \alpha$ で押さえられます。つまり最初の関門で偽陽性を出す確率自体が $\alpha$ 以下に抑えられており、step-down の打ち切り規則によってそれ以降に偽陽性が増えることもありません。結果として、Holm 法は Bonferroni と同じ FWER 保証を持ちながら、必ず Bonferroni 以上の数を棄却できる(=検出力で勝る)という、まさに上位互換の関係になっています。

Bonferroni と Holm はどちらも独立性を仮定しませんでした。一方、検定が独立であることがわかっているなら、もう少し攻めた補正ができます。それが Šidák 補正です。

Šidák 補正:独立性を使って一歩攻める

Bonferroni はブールの不等式という「ゆるい上界」を使っていました。検定が独立だとわかっている場合は、FWER $=1-(1-\alpha)^m$ という等式を直接使えるので、もっと正確(やや緩め)な閾値を設定できます。

各検定の閾値を $\alpha_{\text{Šidák}}$ としたとき、独立性の下で FWER をちょうど $\alpha$ にする条件は

$$ 1 – (1 – \alpha_{\text{Šidák}})^m = \alpha $$

です。これを $\alpha_{\text{Šidák}}$ について解きます。両辺を整理して $(1 – \alpha_{\text{Šidák}})^m = 1 – \alpha$、両辺の $m$ 乗根を取ると $1 – \alpha_{\text{Šidák}} = (1-\alpha)^{1/m}$、よって

$$ \alpha_{\text{Šidák}} = 1 – (1 – \alpha)^{1/m} $$

が得られます。これが Šidák 補正 の閾値です。$m=20$, $\alpha=0.05$ なら $\alpha_{\text{Šidák}} = 1 – 0.95^{1/20} \approx 0.00256$ となり、Bonferroni の $0.05/20 = 0.0025$ よりほんのわずかに大きい(緩い)値です。

実用上、Šidák の利得は Bonferroni に比べてごくわずかです。さらに「独立」という前提は実データではしばしば成り立たないため、安全側の Bonferroni や Holm が選ばれることが多いのが実情です。Šidák は「独立性を仮定すれば Bonferroni を少しだけ改善できる」という理論的な位置づけと覚えておけば十分です。

ここまでの3手法(Bonferroni・Holm・Šidák)はすべて FWER を制御するものでした。発想を「偽陽性ゼロ」から「偽陽性の割合」へと大きく転換するのが、次に見る Benjamini-Hochberg 法です。

Benjamini-Hochberg:FDR を制御する現代の標準

考え方

数万検定を行うゲノミクスでは、FWER をゼロに近づけようとすると検出力がほぼ消えてしまいます。そこで Benjamini と Hochberg は1995年、「偽陽性をゼロにするのは諦めて、発見の中の偽陽性の割合(FDR)を抑える」という発想の転換を提案しました。これが Benjamini-Hochberg 法(BH 法) です。今やゲノミクス・A/Bテスト・脳画像解析の事実上の標準になっています。

手順

目標 FDR を $q$(たとえば 0.05 や 0.10)とします。

  1. p値を小さい順にソートして $p_{(1)} \leq p_{(2)} \leq \cdots \leq p_{(m)}$ とする。
  2. 各順位 $i$ について、$p_{(i)} \leq \dfrac{i}{m} q$ を満たすかを調べる。
  3. これを満たす最大の $i$ を $k$ とする。
  4. $p_{(1)}, \dots, p_{(k)}$ をすべて棄却する(途中で条件を満たさない順位があっても、$k$ までは一括で棄却)。

Bonferroni のように一律の閾値ではなく、順位に比例して緩む閾値 $\frac{i}{m}q$ を使うのがポイントです。最も小さい p値には $\frac{1}{m}q$(Bonferroni 並みに厳しい)、最大の p値には $\frac{m}{m}q = q$(とても緩い)が課されます。

Benjamini-Hochberg手順のp値ソートとi/m*qライン

この図は、ソートした20個の p値(青い点)と BH の直線 $\frac{i}{m}q$(水色、$q=0.1$)を示しています。手順では「点が直線を下回る最大の順位 $i=k$ を見つけ、そこまで全部棄却」します。この例では $k=4$ で、左から4個(赤い丸で囲まれた点)が棄却されました。無補正の閾値 0.05(灰色の破線)と比べると、BH の直線は右に行くほど高くなり、上位の p値には緩い基準を許しているのがわかります。これにより、Bonferroni では拾えなかった「ほどほどに小さい p値」も発見できます。

なぜこれで FDR が $q$ 以下になるのか

BH 法が $\mathrm{FDR} \leq \frac{m_0}{m} q \leq q$ を保証することは、Benjamini と Hochberg によって証明されています($m_0$ は真の帰無仮説の数)。証明の核心だけ直感的に述べます。BH の閾値を満たす最大順位 $k$ で止めるとき、棄却された $k$ 個の中に含まれる偽陽性の期待割合を考えます。真の帰無仮説の p値は一様分布に従う(p値の記事参照)ので、閾値 $\frac{k}{m}q$ を下回る帰無仮説の期待数は $m_0 \cdot \frac{k}{m}q$ です。これを発見数 $k$ で割ると、

$$ \frac{V}{R} \approx \frac{m_0 \cdot \frac{k}{m}q}{k} = \frac{m_0}{m}q \leq q $$

となり、FDR が $q$ 以下に抑えられます。最後の不等号は $m_0 \leq m$(真の帰無は全体以下)によります。直線の傾きを $\frac{q}{m}$ に取ったこと自体が、「発見数に比例して許容偽陽性数も増やす」という FDR の定義にぴたりと適合しているのです。

依存がある場合:Benjamini-Yekutieli

BH 法は、検定が独立または「正の相関」を持つ場合に FDR を保証します。任意の依存構造(負の相関も含む)でも保証したい場合は、閾値を調和級数 $c(m) = \sum_{i=1}^{m} \frac{1}{i}$ で割った Benjamini-Yekutieli 法(BY 法) を使います。BY はより保守的(厳しい)ですが、どんな依存構造でも FDR を守ります。多くの実務では検定が正相関なので BH で十分ですが、依存が読めない場合の保険として BY を覚えておくとよいでしょう。

理論が出そろいました。では実際の場面で、これらをどう使い分ければよいのでしょうか。検出力と偽陽性のトレードオフを軸に整理します。

どれを使うか:検出力と偽陽性のトレードオフ

検出力で比べる

同じデータに各手法を適用したとき、真の効果をどれだけ検出できるか(検出力)が大きく異なります。後の Python シミュレーション(100検定中20個に真の効果、効果サイズ $z=3.0$)の結果を先取りすると、検出力は次のようになりました。

  • 無補正:0.86(最も高いが偽陽性も多い)
  • Bonferroni:0.32
  • Holm:0.32(Bonferroni をわずかに上回る)
  • BH(FDR):0.62

各手法の検出力比較バー

この図は4手法の検出力を比較したものです。無補正(0.86)は最も検出力が高いものの、偽陽性を制御できていません。FWER を守る Bonferroni と Holm は 0.32 前後と低く、保守性の代償が検出力に表れています。BH(0.62)はその中間で、偽陽性の割合を抑えながらも FWER 法の倍近い検出力を確保しています。「広く拾いたい」探索的解析で BH が選ばれる理由が、この数字に凝縮されています。

偽陽性数で比べる

逆に、偽陽性をどれだけ抑えられるかも見てみましょう。別のシミュレーション(100検定中10個に真の効果)での1解析あたり平均偽陽性数は次の通りです。

  • 無補正:4.27(90個の帰無に対し約4個も誤検出)
  • Bonferroni:0.04
  • Holm:0.04
  • BH(FDR):0.33

各手法の平均偽陽性数の比較

この図から、無補正では平均4.27個もの偽陽性が出ているのに対し、FWER を守る Bonferroni・Holm はほぼゼロ(0.04個)に抑えられているのがわかります。BH は 0.33個と、FWER 法よりは多いものの無補正の1/13程度。前の検出力の図と合わせて読むと、FWER 法は偽陽性を徹底的に潰す代わりに検出力を犠牲にし、BH は少数の偽陽性を許す代わりに検出力を稼ぐという、両者のトレードオフがはっきり浮かび上がります。

手法選択ガイド

以上を踏まえると、選択の指針は次のように整理できます。

多重比較補正の手法選択フローチャート

このフローチャートの通り、まず「偽陽性が1個でも出ると致命的か」を問います。YES(医薬の最終判定・安全性評価など)なら FWER 制御を選び、その中では万能で検出力に優れる Holm 法を第一候補に、単純さを重視するなら Bonferroni を。NO(探索的に発見数を増やしたい)なら FDR 制御を選び、独立または正相関なら BH 法、依存構造が読めないなら BY 法を使います。実務的には、数万検定のゲノミクスや多指標 A/Bテストでは BH、少数の確証的な検定では Holm が定番の選択です。

理論と使い分けがわかったところで、実際に Python で動かしてみましょう。

Python での実装(statsmodels multipletests)

multipletests を使う

Python では statsmodels.stats.multitest.multipletests 一つで、ここまでの全手法を実行できます。まずは基本の使い方です。

import numpy as np
from statsmodels.stats.multitest import multipletests

# 10個の検定の生p値(小さいものが「真の効果」候補)
pvals = np.array([0.001, 0.008, 0.012, 0.030, 0.045,
                  0.06, 0.21, 0.38, 0.55, 0.81])

methods = {
    "Bonferroni": "bonferroni",
    "Holm":       "holm",
    "Šidák":      "sidak",
    "BH (FDR)":   "fdr_bh",
}

print(f"{'手法':<12}{'棄却された検定のインデックス'}")
for name, key in methods.items():
    reject, p_adj, _, _ = multipletests(pvals, alpha=0.05, method=key)
    idx = np.where(reject)[0].tolist()
    print(f"{name:<12}{idx}")

multipletests の戻り値は (reject, pvals_corrected, alphacSidak, alphacBonf) の4つです。reject が各検定を棄却するか否かの真偽値配列、pvals_corrected が補正後 p値(これが $\alpha$ を下回れば棄却)です。このコードを実行すると、Bonferroni と Holm はごく一部(p値が極端に小さいもの)しか棄却しないのに対し、BH はより多くの検定を棄却することがわかります。同じ生 p値でも、手法によって「発見の数」が大きく変わるのが多重比較補正の本質です。

補正後 p値の意味

補正後 p値(adjusted p-value)は、「この補正法のもとで棄却するために必要な閾値が $\alpha$ になるよう、生 p値を変換した値」です。たとえば Bonferroni の補正後 p値は $\min(m \cdot p_i, 1)$ で、これが $\alpha$ を下回るかどうかは生 p値が $\alpha/m$ を下回るかどうかと同値です。補正後 p値を使えば、閾値はいつも $\alpha$ のまま比較できるので便利です。

FWER を本当に守れているかシミュレーション

理論で導いた「補正なしでは FWER が膨らむ」「補正すると $\alpha$ 以下に抑えられる」を、シミュレーションで確かめます。すべての帰無仮説が真(効果なし)の状況を多数回作り、少なくとも1個偽陽性が出た割合(=FWER の推定値)を測ります。

import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests

rng = np.random.default_rng(0)
m = 20          # 検定の数
alpha = 0.05
n_sim = 20000   # シミュレーション回数

count = {"無補正": 0, "Bonferroni": 0, "Holm": 0, "BH(FDR)": 0}
for _ in range(n_sim):
    # 全て帰無が真:標準正規からのzで両側p値を作る
    z = rng.normal(0, 1, m)
    p = 2 * (1 - stats.norm.cdf(np.abs(z)))

    if (p < alpha).any():                                   count["無補正"] += 1
    if multipletests(p, alpha, "bonferroni")[0].any():      count["Bonferroni"] += 1
    if multipletests(p, alpha, "holm")[0].any():            count["Holm"] += 1
    if multipletests(p, alpha, "fdr_bh")[0].any():          count["BH(FDR)"] += 1

print(f"検定数 m={m}, 全て帰無が真, {n_sim}回シミュレーション")
for name, c in count.items():
    print(f"  {name:<12} FWER(少なくとも1個偽陽性) = {c / n_sim:.3f}")

このコードを実行すると、無補正の FWER は理論値 $1 – 0.95^{20} \approx 0.64$ に近い値になります。一方、Bonferroni・Holm・BH はいずれも FWER を 0.05 前後(またはそれ以下)に抑えています。全帰無が真の場合、FDR を抑える BH も結果的に FWER を守ること(このとき FDR=FWER になる)が数値で確認できます。理論で証明した FWER 制御が、実装でもそのまま成り立っているのです。

検出力と偽陽性を測る(手法比較)

次に、一部に真の効果がある現実的な状況で、各手法の検出力と偽陽性数を測ります。本記事の図7・図8と同じ設定です。

import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests

def evaluate(m, m_alt, effect, n_sim, alpha=0.05, q=0.05, seed=2024):
    """検出力(真の効果の検出割合)と平均偽陽性数を返す"""
    rng = np.random.default_rng(seed)
    methods = {"無補正": None, "Bonferroni": "bonferroni",
               "Holm": "holm", "BH(FDR)": "fdr_bh"}
    power = {k: 0.0 for k in methods}
    fpos  = {k: 0.0 for k in methods}

    for _ in range(n_sim):
        z = rng.normal(0, 1, m)
        z[:m_alt] += effect                       # 先頭m_alt個に真の効果
        p = 2 * (1 - stats.norm.cdf(np.abs(z)))
        for name, key in methods.items():
            if key is None:
                rej = p < alpha
            else:
                a = q if key == "fdr_bh" else alpha
                rej = multipletests(p, a, key)[0]
            power[name] += rej[:m_alt].sum() / m_alt   # 真の効果のうち検出した割合
            fpos[name]  += rej[m_alt:].sum()           # 帰無領域での棄却=偽陽性
    power = {k: v / n_sim for k, v in power.items()}
    fpos  = {k: v / n_sim for k, v in fpos.items()}
    return power, fpos

pw, _ = evaluate(m=100, m_alt=20, effect=3.0, n_sim=400)
_, fp = evaluate(m=100, m_alt=10, effect=3.2, n_sim=400, seed=99)

print("検出力 (m=100, 真の効果20個, z=3.0):")
for k, v in pw.items():
    print(f"  {k:<12} {v:.3f}")
print("平均偽陽性数 (m=100, 帰無90個, z=3.2):")
for k, v in fp.items():
    print(f"  {k:<12} {v:.3f}")

このコードを実行すると、検出力は無補正 0.86、Bonferroni 0.32、Holm 0.32、BH 0.62 前後となり、偽陽性数は無補正 4.27、Bonferroni 0.04、Holm 0.04、BH 0.33 前後になります(図7・図8と一致)。BH は FWER 法の倍近い検出力を持ちつつ、偽陽性を無補正の1/13に抑えるという、検出力と頑健性のバランスが数値で確認できます。どの手法も「無補正よりは偽陽性を劇的に減らす」点は共通で、補正の有無こそが最も大きな差を生むことも見て取れます。

自前で BH を実装して理解を深める

ライブラリ任せでは仕組みが見えないので、BH 法を素朴に実装して multipletests と一致することを確かめます。

import numpy as np
from statsmodels.stats.multitest import multipletests

def bh_reject(pvals, q=0.05):
    """Benjamini-Hochberg を手で実装。棄却フラグを返す"""
    m = len(pvals)
    order = np.argsort(pvals)            # 小さい順のインデックス
    p_sorted = pvals[order]
    thresh = (np.arange(1, m + 1) / m) * q   # i/m * q のライン
    below = p_sorted <= thresh
    if not below.any():
        return np.zeros(m, dtype=bool)
    k = np.max(np.where(below)[0])       # 条件を満たす最大の順位(0始まり)
    reject_sorted = np.zeros(m, dtype=bool)
    reject_sorted[:k + 1] = True         # k番目まで一括で棄却
    reject = np.zeros(m, dtype=bool)
    reject[order] = reject_sorted        # 元の並びに戻す
    return reject

# 検証
rng = np.random.default_rng(7)
pvals = np.sort(rng.beta(0.5, 8, 20))    # 小さめのp値が多めの例
mine = bh_reject(pvals, q=0.1)
lib  = multipletests(pvals, alpha=0.1, method="fdr_bh")[0]
print("自前BHとstatsmodelsが一致:", np.array_equal(mine, lib))
print("棄却数:", mine.sum())

このコードを実行すると 自前BHとstatsmodelsが一致: True と表示され、手順通りの実装がライブラリと完全に一致することが確認できます。ポイントは「条件 $p_{(i)} \leq \frac{i}{m}q$ を満たす最大順位 $k$ を見つけ、$k$ 番目までを一括棄却する」という step-up の論理です。途中に条件を満たさない順位があっても、$k$ までは棄却する点が Holm(step-down)との違いです。仕組みを手で書くことで、図5で見た「直線との交差点」の意味が腑に落ちるはずです。

実装で各手法の挙動を確認できました。最後に、これらが実際の研究現場でどう使われ、どんな落とし穴(p値ハッキング)と結びついているかを見ましょう。

応用:ゲノミクス・A/Bテスト・脳画像・p値ハッキング

遺伝子発現解析(数万検定)

最も多重比較補正が活躍するのがゲノミクスです。マイクロアレイや RNA-seq では、2万個前後の遺伝子それぞれについて「病気の群と健常群で発現量に差があるか」を一斉に検定します。$m=20{,}000$ で補正なしなら、効果のない遺伝子だけでも約1000個($20000 \times 0.05$)が「有意」と誤判定されてしまいます。これでは結果が使い物になりません。

ここで FWER(Bonferroni)を使うと閾値が $0.05/20000 = 2.5\times 10^{-6}$ と極端に厳しくなり、真の差まで潰してしまいます。そこで標準となるのが BH 法による FDR 制御です。「発見した遺伝子のうち偽物は5%まで」という基準なら、何百個もの候補遺伝子を効率よく拾えます。結果は volcano plot(横軸に発現変化 $\log_2$ fold change、縦軸に $-\log_{10} p$)で可視化するのが定番です。

遺伝子発現のVolcano plotとFDR補正の効果

この volcano plot は5000遺伝子の解析を表しています。灰色は非有意、オレンジは「無補正なら有意だが BH では落ちる」遺伝子(その多くは偽陽性)、赤は BH(FDR<0.05) でも有意な遺伝子です。中央付近(発現変化が小さい領域)にオレンジが大量に分布しているのに注目してください。これらは無補正の 0.05 だけでは「有意」と誤判定される偽陽性候補で、FDR 補正によってきれいに除去されています。一方、左右の端(発現変化が大きく p値も極めて小さい)の赤い点は、補正後も確実に残る真の発見です。FDR 補正が「効果の薄い偽陽性を削り、本物だけを残す」フィルタとして働いているのが視覚的にわかります。

A/Bテストの多変量問題

Webサービスの改善では、新デザイン案について「クリック率」「滞在時間」「コンバージョン率」「離脱率」…と多数の指標を同時に比較しがちです。指標が10個もあれば、たとえ新案に効果がなくても、どれか一つが偶然「有意に改善」と出る確率は約40%。これを根拠に新案を採用すると、効果のない変更を「成功」と勘違いしてしまいます。複数指標・複数バリアントを同時に検定するときは、BH 法で FDR を制御するのが堅実です。確証的に「この1指標で勝つか」を判定したいなら、Holm で FWER を守ります。

脳画像解析(fMRI)

fMRI では脳を数万個のボクセルに分割し、各ボクセルで「課題中に活動が増えたか」を検定します。$m$ が数万に達するため、補正なしでは偶然有意なボクセルが脳全体に散らばってしまいます。有名なパロディとして、死んだ鮭の脳の fMRI で補正をかけずに検定すると「鮭が画像に反応した」ボクセルが検出された、という研究があります。これは多重比較補正の必要性を象徴する事例で、脳画像分野では FDR 制御やランダムフィールド理論に基づく FWER 制御が必須とされています。

p値ハッキングとの関係

多重比較問題は p値ハッキング(p-hacking) と深く結びついています。p値ハッキングとは、有意な結果が出るまで分析を繰り返す行為——たくさんの変数・部分集団・解析手法を試し、たまたま $p<0.05$ になったものだけを報告すること——です。これは事実上「報告されない多重比較」であり、報告された1個の p値の裏に隠れた検定回数 $m$ が補正されていないため、FWER が制御不能に膨らみます。

防ぐ鍵は、何回検定したかを正直に数え、適切に補正することです。事前に解析計画を登録(事前登録、preregistration)し、検定の家族を明示し、Holm や BH で補正する。こうした規律こそが、多重比較補正の本当の目的——「偶然の有意」に騙されない誠実な科学——を支えています。多重比較補正は単なる計算テクニックではなく、研究の信頼性を守る倫理的な装置でもあるのです。

まとめ

本記事では、検定を繰り返すと偽陽性が増える多重比較問題と、その代表的な補正法について、直感・数理・実装の3面から解説しました。

  • 多重比較問題:$m$ 個の独立な検定をすべて有意水準 $\alpha$ で行うと、少なくとも1個偽陽性が出る確率(FWER)は $1-(1-\alpha)^m$ に膨らむ。$m=20$, $\alpha=0.05$ で約 0.64。
  • FWER と FDR:FWER $=P(V\geq 1)$ は「1個でも偽陽性を出す確率」、FDR $=E[V/R]$ は「発見の中の偽陽性の割合」。前者は厳格、後者は探索的。
  • Bonferroni:閾値を $\alpha/m$ にする。ブールの不等式から FWER $\leq\alpha$ を独立性なしで保証するが、保守的で検出力が低い。
  • Holm:p値を昇順に並べ閾値を $\alpha/(m-i+1)$ と段階的に緩める step-down 法。Bonferroni と同じ FWER 保証を持ちつつ検出力で上回る上位互換。
  • Šidák:独立性を仮定し $\alpha_{\text{Šidák}}=1-(1-\alpha)^{1/m}$。Bonferroni をわずかに緩める。
  • Benjamini-Hochberg:閾値 $\frac{i}{m}q$ を満たす最大順位まで一括棄却し FDR を $q$ 以下に制御。ゲノミクス・A/Bテスト・脳画像の標準。
  • 使い分け:偽陽性1個が致命的なら Holm(FWER)、多くの候補を広く拾いたいなら BH(FDR)。

Python では statsmodels.stats.multitest.multipletests 一つで全手法を実行でき、シミュレーションでは BH が FWER 法の倍近い検出力(0.62 vs 0.32)を保ちながら偽陽性を無補正の1/13に抑えることを確認しました。多重比較補正は、p値ハッキングを防ぎ研究の信頼性を守るための、データ解析の必須教養です。

次のステップとして、以下の記事も参考にしてください。