全確率の公式とベイズの定理 — 確率推論の二大基本則を完全理解

「ある病気の有病率は1000人に1人。検査の感度は99%、特異度は95%。あなたが検査を受けて陽性だった。あなたが本当に病気である確率は?」——多くの人は直感的に「90%以上」と答えますが、正しい答えはわずか 約2% です。この圧倒的な直感のずれを生む元凶を解きほぐすには、全確率の公式(law of total probability)と ベイズの定理(Bayes’ theorem)という双子の基本則を理解する必要があります。

全確率の公式は「直接求めにくい確率を、場合分けして条件付き確率の重み付き和に分解する」道具です。一方、ベイズの定理は「観測されたデータから、その原因となった仮説の確率を逆方向に更新する」道具。両者は表裏一体で、ベイズの定理の分母は必ず全確率の公式で計算されます。

この2つを押さえれば、以下のような現代の確率推論の主要な応用が一気に視界に入ります。

  • スパムメールフィルタ: 単語の出現頻度から「このメールがスパムである確率」を逆算する(ナイーブベイズ分類)
  • 医療検査の解釈: 陽性結果が出たときの真の有病確率(疾病前確率の補正)
  • モンティ・ホール問題: 3つのドアの確率パラドックスの正解
  • 通信路復号: 受信ビットから送信ビットを推定する最尤・MAP復号
  • 物体認識・故障診断: 観測された特徴から物体クラスや故障原因を推定
  • マルコフ連鎖: 状態遷移確率から定常分布や予測分布を計算する

本記事の内容

  • 全確率の公式・ベイズの定理の直感的理解と数学的導出
  • 両者の関係(全確率の公式はベイズの定理の分母である)
  • 典型問題: モンティ・ホール / 医療検査 / 品質管理 / スパム判定
  • ナイーブベイズ分類器のスクラッチ実装(スパム/非スパム分類)
  • ベイズ更新の可視化(逐次データから事後分布が形を変える様子)
  • 連続版(混合分布・周辺化)と全期待値・全分散の定理

全確率の公式の概念図:工場A/B/Cで場合分けし、生産比率で重み付けして足し上げると全体の不良品率が求まる

全確率の公式が何をしているのかを1枚にまとめたのが上の図です。3つの工場それぞれについて「その工場で作られる確率 $P(A_i)$」と「その工場での不良品率 $P(D\mid A_i)$」を掛け、最後に足し上げる。掛け算が「そのケースでの寄与」、足し算が「ケースを網羅する」役割を担っています。工場Cの不良品率は5%と一番高いのに寄与は 0.010 でしかなく、不良品率2%の工場Aと同じ——重みが効いていることが数値で見て取れます。この「重み付けして足す」という一手が本記事の全ての土台です。

前提知識

この記事を読む前に、以下の記事に目を通しておくと一気に理解が深まります。

これらが未読でも本記事単独で読み進められるよう、必要な定義は最低限内部で復習します。

直感 — 場合分けで全確率を組み立てる

クラス別合格率の例

ある大学の統計学の試験で、A組(40人)の合格率は80%、B組(60人)の合格率は60%でした。では、全体100人の合格率はいくらでしょうか?

単純に $(80 + 60)/2 = 70\%$ と平均してしまうのは典型的な誤りです。2つのクラスの人数が異なるため、各クラスの合格率を 人数比で重み付け して平均しなければなりません。

$$ \text{全体合格率} = \frac{40}{100}\times 0.80 + \frac{60}{100}\times 0.60 = 0.32 + 0.36 = 0.68 $$

すなわち68%です。「クラスごとに条件付き確率を計算し、各クラスの割合を重みにして合計する」——この手順を一般化したものが全確率の公式そのものです。

通勤遅刻の例

もう一つ別の文脈で直感を補強しましょう。「明日通勤に遅刻する確率」を知りたいとします。遅刻のしやすさは天気に強く依存するので、天気を「晴れ・雨・雪」の3つに場合分けして考えます。

天気 天気予報の確率 遅刻する確率
晴れ 0.70 0.05
0.25 0.20
0.05 0.60

「遅刻する確率」を直接見積もるのは難しいですが、「天気が決まっていれば遅刻のしやすさは見積もれる」というのが場合分けの効能です。各場合について「天気の確率 × その天気の下での遅刻確率」を足し合わせれば、

$$ 0.70\times 0.05 + 0.25\times 0.20 + 0.05\times 0.60 = 0.035 + 0.050 + 0.030 = 0.115 $$

明日遅刻する全体の確率は11.5%だとわかります。

この計算が「全確率の公式」

2つの例に共通する構造を抜き出すと、「考えたい事象 $A$」と「お互いに排反で全体を覆い尽くす場合分け $B_1, B_2, \ldots, B_n$」があり、

$$ P(A) = \sum_i \underbrace{P(B_i)}_{\text{場合の確率}}\times \underbrace{P(A\mid B_i)}_{\text{その場合における } A \text{ の確率}} $$

という形になっています。この単純な式が、これから定式化していく全確率の公式です。次のセクションで、定式化に必要な条件付き確率を一度だけ復習しておきましょう。

条件付き確率の復習

全確率の公式・ベイズの定理は、いずれも条件付き確率の上に成り立っています。簡単に確認しておきます。

定義

事象 $B$ が起きたという情報の下での事象 $A$ の確率を、条件付き確率 といい次で定義します。

$$ P(A\mid B) = \frac{P(A\cap B)}{P(B)}\quad (P(B) > 0) $$

これは「$B$ が起きた世界」だけを取り出して、その中で $A$ が起きる割合を測っていると解釈できます。標本空間を $B$ に限定して、確率の総和が1になるように $P(B)$ で割って正規化しているわけです。

乗法定理

定義式を機械的に変形すると、

$$ P(A\cap B) = P(A\mid B)P(B) = P(B\mid A)P(A) $$

これを 乗法定理 あるいは 積の公式 と呼びます。同じ同時確率 $P(A\cap B)$ を、$B$ を先に観測する見方と、$A$ を先に観測する見方の2通りに分解できるという主張です。乗法定理は次セクション以降で繰り返し使う最重要道具なので、形を覚えておいてください。

これで準備は整ったので、いよいよ全確率の公式を厳密に定式化します。

全確率の公式の導出と典型例

標本空間の分割

全確率の公式の心臓部にあるのは 標本空間の分割(partition)という概念です。標本空間 $\Omega$ 上の事象列 $\{A_1, A_2, \ldots, A_n\}$ が分割をなすとは、以下の2条件を満たすことです。

  1. 排反性: $A_i \cap A_j = \emptyset$ ($i\neq j$)。場合が決して重ならない。
  2. 網羅性: $A_1 \cup A_2 \cup \cdots \cup A_n = \Omega$。場合が全標本を覆い尽くす。

この2条件はそれぞれ「ちょうど1つだけが起こる」を保証します。前節の天気の例では、$A_1=\{\text{晴}\}, A_2=\{\text{雨}\}, A_3=\{\text{雪}\}$ がまさに分割をなしていました。

定理の主張

$\{A_1,\ldots,A_n\}$ が $\Omega$ の分割で、全ての $i$ について $P(A_i) > 0$ とする。このとき任意の事象 $B$ に対して、

$$ \begin{equation} P(B) = \sum_{i=1}^{n} P(B\mid A_i)\,P(A_i) \end{equation} $$

これが 全確率の公式 です。事象 $B$ の確率は、各場合 $A_i$ の下での条件付き確率を、$A_i$ 自身の確率で重み付けして合計したものに等しい、と読めます。

証明

証明はほぼ機械的です。分割の網羅性から $\Omega = \bigcup_i A_i$。したがって、

$$ B = B\cap \Omega = B \cap \left(\bigcup_{i=1}^{n} A_i\right) = \bigcup_{i=1}^{n}(B\cap A_i) $$

$A_i$ が排反なので、$B\cap A_i$ も互いに排反です。確率の加法性から、

$$ P(B) = \sum_{i=1}^{n} P(B\cap A_i) $$

ここで乗法定理 $P(B\cap A_i) = P(B\mid A_i)P(A_i)$ を代入すると、

$$ P(B) = \sum_{i=1}^{n} P(B\mid A_i)P(A_i) $$

となり、全確率の公式が得られます。

ベン図によるイメージ

全確率の公式はベン図で見ると一目瞭然です。標本空間 $\Omega$ を分割 $A_1, A_2, A_3$ で3つの領域に切り分けると、任意の事象 $B$ は各領域との交わり $B\cap A_1, B\cap A_2, B\cap A_3$ に重なりなく細切れになります。各切れ端の面積を全部足せば $B$ 全体の面積になる——これが全確率の公式の幾何学的中身です。

「直接 $B$ の面積を測るのは難しいけれど、$A_i$ の枠の中だけなら $B$ の面積比は測りやすい」という状況で威力を発揮します。たとえば「明日の遅刻確率」は直接見積もりにくいですが、「晴れの日の遅刻確率」「雨の日の遅刻確率」「雪の日の遅刻確率」ならば過去のデータから比較的安定に見積もれる、というのが分割を導入する意義です。

標本空間の分割と、事象Bが各A_iとの交わりに重なりなく切り分けられる様子

左が分割の条件、右が証明の中身です。左では $A_1,\dots,A_4$ が隙間なく・重なりなく標本空間 $\Omega$ を覆っています。右では事象 $B$(赤い楕円)がこの区画線でちょうど $B\cap A_2$ と $B\cap A_3$ に切り分けられ、$A_1$ と $A_4$ とは交わりを持ちません。切れ端は互いに素なので面積を単純に足してよく、各切れ端を $P(B\mid A_i)P(A_i)$ と書き直せばそのまま公式になります。証明が3行で終わるのは、この「重ならない」という分割の性質がすべての仕事をしているからです。

二分割の特別な場合

最もよく現れるのは、分割が2つだけのとき、$\{A, \bar A\}$ ($\bar A$ は $A$ の補集合)の場合です。このとき全確率の公式は、

$$ P(B) = P(B\mid A)P(A) + P(B\mid \bar A)P(\bar A) $$

と書けます。後で出てくる医療検査の例(病気か非病気か)、通信の例(0送信か1送信か)、スパム判定(スパムか非スパムか)はすべてこのパターンです。「YES/NOの二択 + その下での観測確率」という構造は確率モデリングの最頻出ケースですから、まずはこの形を体に染み込ませると応用の幅が広がります。

典型例: 工場別不良品率

3つの工場で生産される製品の不良品率を題材に、全確率の公式を適用してみます。

工場 生産比率 $P(A_i)$ 不良品率 $P(D\mid A_i)$
工場A 0.50 0.02
工場B 0.30 0.03
工場C 0.20 0.05

製品からランダムに1個取り出したとき、それが不良品である確率 $P(D)$ は、

$$ P(D) = 0.02\times 0.50 + 0.03\times 0.30 + 0.05\times 0.20 = 0.010 + 0.009 + 0.010 = 0.029 $$

全体の不良品率は2.9%です。工場ごとの不良品率(2〜5%)を、生産量で重み付けして加重平均したものになっています。

工場例の面積図と、事前確率・事後確率の棒グラフ比較

左の図は横幅を生産比率、縦を不良品率にとった面積図です(縦は見やすさのため10倍に拡大)。塗りつぶした部分の面積がそのまま各工場の寄与 $P(D\mid A_i)P(A_i)$ になり、3つの面積の合計 0.029 が $P(D)$ です。横に広くて背の低い工場A(0.010)と、横に狭くて背の高い工場C(0.010)が同じ面積になっているのが印象的です。右の図は先取りになりますが、不良品と分かった後の「どの工場か」の確率を並べたもので、生産量が多い工場Aは不良率が最低にもかかわらず出所としては最多タイ(34.5%)になります。

ここで、もし不良品が出てきたとき「どの工場で作られた確率が高いか」を逆算したくなりますよね。これがまさにベイズの定理の出番です。

ベイズの定理の導出

二つの乗法定理から1分で出る

乗法定理を二方向に書きます。

$$ P(A\cap B) = P(A\mid B)P(B) = P(B\mid A)P(A) $$

中央と右辺を等号で結び、両辺を $P(B) > 0$ で割れば、

$$ \begin{equation} P(A\mid B) = \frac{P(B\mid A)P(A)}{P(B)} \end{equation} $$

これが ベイズの定理 です。導出は1行で済む単純な式ですが、その意味は深遠です。

なぜ条件付けの「向き」を変える操作が価値を持つのか

応用上、$P(B\mid A)$ は推定しやすい一方、$P(A\mid B)$ は知りたいけれど直接測れない、というケースが圧倒的に多いことに注意します。たとえば医療検査では、

  • 測りやすい: 「病気の人に検査した時の陽性率」 $P(+\mid D)$ → 臨床試験で測定可能
  • 知りたい: 「陽性結果が出た人が病気である確率」 $P(D\mid +)$ → 一人ひとりの患者にとって本当に関心のある量

両者の方向は 全く別物 で、特に低い有病率の下ではしばしば桁が違います。ベイズの定理は、測りやすい方向の確率から、知りたい方向の確率へ「向きを反転させる」唯一の道具なのです。

各項の名前

ベイズの定理の各項にはそれぞれ専用の呼び名がついており、確率推論の文脈で頻出します。

名前 意味
$P(A)$ 事前確率 (prior) データ $B$ を見る前の $A$ の確率
$P(B\mid A)$ 尤度 (likelihood) $A$ を仮定したときに $B$ が観測される確率
$P(B)$ エビデンス, 周辺尤度 データ $B$ の全体としての出現確率
$P(A\mid B)$ 事後確率 (posterior) データ $B$ を見た後の $A$ の確率

ベイズの定理は「事前確率 × 尤度 / エビデンス = 事後確率」という構造です。式全体は「観測されたデータ $B$ に整合するように、仮説 $A$ の確率を更新する手続き」と読めます。

ベイズの定理の各項の名前と役割:事後確率・尤度・事前確率・周辺尤度

4つの項に名前が付いているのは、それぞれ役割がまるで違うからです。尤度 $P(B\mid A)$ は「原因が分かっているときに結果がどう出るか」で、臨床試験や工場の検査など実験で測れる量です。一方で本当に知りたい事後確率 $P(A\mid B)$ は測れません。ベイズの定理は、測れる尤度と手持ちの事前確率から測れない事後確率を作り出す変換装置だと見るとしっくりきます。分母の $P(B)$ が全確率の公式そのものである点は次節で詳しく扱います。

仮説が複数ある一般形

仮説の側が複数 $A_1,\ldots,A_n$ あり、これらが標本空間の分割をなす場合、ベイズの定理は次の形になります。

$$ \begin{equation} P(A_i\mid B) = \frac{P(B\mid A_i)P(A_i)}{\sum_{k=1}^{n} P(B\mid A_k)P(A_k)} \end{equation} $$

ここで分母には、まさに全確率の公式が出てきています。これが「全確率の公式は ベイズの定理の分母 である」という、両者の最も重要な関係です。

両者の関係 — 全確率の公式はベイズの定理の分母

表と裏の関係

ベイズの定理の分母 $P(B)$ は、典型的なケースでは直接観測できません。観測できるのは「仮説 $A_i$ それぞれの下で、データ $B$ がどれくらい出やすいか」、すなわち尤度 $P(B\mid A_i)$ と事前確率 $P(A_i)$ だけです。そこで分母を、

$$ P(B) = \sum_i P(B\mid A_i)P(A_i) $$

と全確率の公式で組み立てることが必須になります。「分子は分布の形を決め、分母は正規化定数として総和を1にそろえる」という構造です。

これにより、ベイズの定理を「事前分布 → 事後分布」という更新操作として、一切の周辺化を機械的に書ききることができます。事後確率の合計は、

$$ \sum_{i=1}^{n} P(A_i\mid B) = \sum_{i=1}^{n} \frac{P(B\mid A_i)P(A_i)}{P(B)} = \frac{1}{P(B)}\sum_{i=1}^{n} P(B\mid A_i)P(A_i) = \frac{P(B)}{P(B)} = 1 $$

と必ず1になります。これも全確率の公式が分母に立っているおかげです。

「合成」と「分析」の対

全確率の公式とベイズの定理は、確率推論における 合成分析 の対をなしています。

  • 全確率の公式 (synthesis): 原因 $A_i$ の確率と、各原因が結果 $B$ を引き起こす条件付き確率から、結果 $B$ の全体確率を 構成 する。
  • ベイズの定理 (analysis): 結果 $B$ が観測されたとき、それぞれの原因 $A_i$ がどれくらいありそうかを 逆算 する。

物理学の用語を借りれば「順問題」と「逆問題」の関係です。原因→結果は順問題、結果→原因はベイズによる逆問題、と整理できます。

全確率の公式(合成)とベイズの定理(分析)が原因→結果・結果→原因の対になっている図

同じ材料——各原因の確率 $P(A_i)$ と条件付き確率 $P(B\mid A_i)$——から、進む向きだけを変えた2つの操作が得られます。左の合成は原因側の情報を足し上げて結果の確率を組み立て、右の分析は観測した結果から原因の確からしさを逆算する。そして分析の分母には合成の答えがそのまま入ります。「ベイズを使いたければ、まず全確率で分母を作らなければならない」という順序関係が、この図の矢印の向きに表れています。

工場の例で逆推定

先ほどの工場の例で逆推定をやってみましょう。製品を1つ取って不良品 $D$ だったとき、それが工場Aで作られた確率 $P(A\mid D)$ は、

$$ P(A\mid D) = \frac{P(D\mid A)P(A)}{P(D)} = \frac{0.02\times 0.50}{0.029} = \frac{0.010}{0.029} \approx 0.345 $$

同様に、

$$ P(B\mid D) = \frac{0.03\times 0.30}{0.029} \approx 0.310,\quad P(C\mid D) = \frac{0.05\times 0.20}{0.029} \approx 0.345 $$

合計が0.345+0.310+0.345=1.000となり、確かに事後確率の総和は1です。興味深いのは、不良品率が最も低い工場A (2%) が、不良品の出所として最も確率が高い (34.5%) という点。これは工場Aが生産量で圧倒している(50%)ためで、「事前確率の効果」が「尤度の効果」に勝った例です。事前分布の影響を無視すると判断を誤る、というベイズ統計の重要な教訓がここにあります。

両者の関係が腹落ちしたところで、典型問題に触れて道具に手応えをつけていきます。

典型問題: モンティ・ホール / 医療検査 / スパム判定

1. モンティ・ホール問題

ゲームショーで3つのドアが提示されます。1つの裏には車、2つの裏にはヤギ。あなたはドア1を選びます。すると司会のモンティが、残ったドア2とドア3のうち ヤギのある方 (たとえばドア3) を開けてヤギを見せ、「ドア2に変更しますか?」と聞いてきます。変更すべきでしょうか?

直感的には「残り2つで2分の1」と思えますが、ベイズの定理が示す答えは 変更した方が勝率が2倍になる です。

仮説を $A_1,A_2,A_3$ = 「車がドア1,2,3にある」、観測データ $B$ = 「モンティがドア3を開けてヤギを見せた」とします。事前確率は均等で $P(A_i) = 1/3$。尤度を場合分けして計算します。

  • $A_1$ (車がドア1): あなたが選んだドア1が当たり。モンティは残りの2,3からランダムに選ぶので、$P(B\mid A_1) = 1/2$。
  • $A_2$ (車がドア2): モンティは車のあるドア2を開けられないので、必ずドア3を開ける。$P(B\mid A_2) = 1$。
  • $A_3$ (車がドア3): モンティは車のあるドア3を開けない。$P(B\mid A_3) = 0$。

エビデンスは全確率の公式で、

$$ P(B) = \frac{1}{2}\cdot\frac{1}{3} + 1\cdot\frac{1}{3} + 0\cdot\frac{1}{3} = \frac{1}{6} + \frac{1}{3} = \frac{1}{2} $$

事後確率は、

$$ P(A_1\mid B) = \frac{(1/2)(1/3)}{1/2} = \frac{1}{3},\quad P(A_2\mid B) = \frac{1\cdot (1/3)}{1/2} = \frac{2}{3} $$

ドア1に車がある確率は1/3のまま、ドア2に車がある確率は2/3に倍増。だから変更すべきです。「モンティの行動が情報を持ち込んだ」ことが、$P(B\mid A_2)=1$ と $P(B\mid A_1)=1/2$ の非対称な尤度に反映されています。

この結果は何度シミュレーションしても揺るがず、コンピュータ上で 100,000 回ゲームを繰り返すと、変更したときの勝率が 2/3 に、変えないときの勝率が 1/3 に確かに収束します。条件付き確率の非自明さを示す古典的なパラドックスで、確率推論の練習問題として極めて教育的価値が高い問題です。

モンティ・ホール問題の尤度の場合分け表と、20万回シミュレーションによる勝率比較

左の表がこの問題の全てです。司会者がドア3を開けるという観測 $B$ に対して、ドア1に車がある場合の尤度は $1/2$(司会者はドア2とドア3のどちらを開けてもよい)、ドア2に車がある場合は $1$(ドア3しか開けられない)と非対称になります。事前確率はどれも $1/3$ で同じなのに、この尤度の差がそのまま事後確率の差になり、$1/3$ 対 $2/3$ が生まれます。右は実際に20万回試行した結果で、変更しない 0.3322 / 変更する 0.6678 と理論値 $1/3, 2/3$ にぴったり一致しました。

2. 医療検査の解釈 — 冒頭の問題

ここで冒頭の問題に戻りましょう。有病率0.1%、感度99%、特異度95%の検査で陽性が出た。本当に病気である確率は?

仮説を $D$=病気、$\bar D$=非病気、データを $+$=陽性とします。

  • 事前確率: $P(D) = 0.001,\quad P(\bar D) = 0.999$
  • 感度 (病気なら陽性): $P(+\mid D) = 0.99$
  • 偽陽性率 (非病気なのに陽性): $P(+\mid \bar D) = 1 – 0.95 = 0.05$

エビデンス $P(+)$ を全確率の公式で計算します。

$$ P(+) = P(+\mid D)P(D) + P(+\mid \bar D)P(\bar D) = 0.99\times 0.001 + 0.05\times 0.999 $$

各項を計算すると、

$$ P(+) = 0.00099 + 0.04995 = 0.05094 $$

ベイズの定理を適用すると、

$$ P(D\mid +) = \frac{P(+\mid D)P(D)}{P(+)} = \frac{0.99\times 0.001}{0.05094} = \frac{0.00099}{0.05094} \approx 0.0194 $$

なんと約 1.94% 。陽性結果が出ても、本当に病気の人は50人に1人しかいません。残り98%は「偽陽性」です。

この衝撃的な結果は、有病率 $P(D)=0.001$ という極小の事前確率が、感度99%という高い尤度を圧倒している例です。「真陽性 0.00099 << 偽陽性 0.04995」という比率がそのまま事後確率に反映されています。ベース・レート(基準割合)を無視すると確率の見積りが2桁ずれる という教訓は、医療・法廷・統計検定など至るところで現れます。

直感的な再解釈として、10,000人の集団を考えてみましょう。有病率0.1%なので病気の人は10人、非病気の人は9,990人。感度99%なので病気の10人のうち約10人が陽性。特異度95%なので非病気の9,990人のうち約500人が偽陽性です。陽性者は合計510人で、そのうち真の病気は10人。すなわち真陽性率は $10/510 \approx 0.0196$ ≈ 1.96%。条件付き確率の計算結果(1.94%)と確かに一致します。「人数の絵」で考えると、偽陽性が真陽性を圧倒する構造が腹落ちしやすいです。

10万人の自然頻度ツリーによる医療検査の解釈と、有病率に対する陽性的中率の変化

左は確率の代わりに「10万人だとしたら何人か」で数えた図です。病気の人は100人しかおらず、そのうち陽性になるのは99人。一方で健康な99,900人のうち5%が誤って陽性になるので4,995人。陽性者5,094人のうち本当に病気なのは99人だけで、1.9%という答えが割り算1回で出ます。右の曲線は感度99%・特異度95%を固定したまま有病率だけを変えたもので、有病率が1%を超えたあたりから的中率が急に立ち上がります。同じ検査でも、誰に対して使うかで意味がまるで変わる——これがスクリーニング検査の設計で最も重要な事実です。

3. スパム判定の素描

スパムメールフィルタは、メール本文に現れる単語 $w_1, w_2, \ldots, w_n$ からそれが スパム ($S$) か 非スパム ($\bar S$) かを判定するシステムです。ナイーブな仮定として「単語の出現は互いに独立」とすると、

$$ P(S\mid w_1,\ldots,w_n) = \frac{P(S)\prod_{i=1}^{n} P(w_i\mid S)}{P(S)\prod_i P(w_i\mid S) + P(\bar S)\prod_i P(w_i\mid \bar S)} $$

分母は全確率の公式そのもの。分子・分母を比較しているだけなので、実用上は対数尤度比、

$$ \log\frac{P(S\mid \mathbf{w})}{P(\bar S\mid \mathbf{w})} = \log\frac{P(S)}{P(\bar S)} + \sum_{i=1}^{n}\log\frac{P(w_i\mid S)}{P(w_i\mid \bar S)} $$

を計算して符号で判定します。これがナイーブベイズ分類器のスパムフィルタです。事前のスパム率(対数オッズ)に 各単語の証拠の寄与(対数尤度比)を足し合わせる、という加法的構造になっており、計算も極めて高速です。

事前確率と尤度比の綱引き:事前が極端に小さいと尤度比が大きくても事後は伸びない

横軸に事前確率(対数)、縦軸に事後確率をとり、尤度比を2から1000まで変えた曲線です。尤度比が1000という極端に強い証拠でも、事前確率が $10^{-4}$ なら事後確率は約9%にしかなりません。曲線はどれも同じ形を横にずらしただけで、尤度比を10倍にすることと事前確率を10倍にすることは同じ効果を持つ(対数オッズの世界では単なる足し算になる)ことが読み取れます。医療検査の1.9%という答えが小さいのは検査が悪いからではなく、事前確率が小さいという一点に尽きるわけです。

4. 検査の連続適用 — 事後確率は次の事前確率

ベイズの定理の使い方で最重要なのは、逐次更新 です。同じ患者に対して独立な検査が2回行われ、1回目が陽性 $+_1$、2回目も陽性 $+_2$ だった場合、

$$ P(D\mid +_1, +_2) = \frac{P(+_2\mid D)\,P(D\mid +_1)}{P(+_2\mid D)P(D\mid +_1) + P(+_2\mid \bar D)P(\bar D\mid +_1)} $$

つまり「1回目の検査の事後確率」を「2回目の検査の事前確率」として再代入するだけで自動的に処理できます。先ほどの $P(D\mid +)\approx 0.0194$ を新たな事前として2回目の検査を解くと、$P(D\mid +_1,+_2) \approx 0.282$ にまで跳ね上がります。疑わしい結果が出たら検査を繰り返す という医療実務上の慣行が、ベイズの定理から自然に正当化されるわけです。

次のセクションでPythonに落とし込みます。

独立な検査を繰り返したときの事後確率の推移:0.1%→1.94%→28.18%→88.60%→99.35%

陽性が出るたびに事後確率を次の事前確率として使い回した結果です。1回目は1.94%とまだ低いままですが、2回目で28.18%、3回目で88.60%、4回目で99.35%と一気に立ち上がります。各回で対数オッズに同じ量($\log 19.8 \approx 2.99$)が足されているので、確率のスケールで見るとS字を描いて急変するように見えるわけです。1回の検査で決めつけず、独立な証拠を重ねることがベイズ推論の実践的な要点だと分かります。

Python実装 — ナイーブベイズ分類器 + ベイズ更新可視化

工場別不良品率の可視化

まずは全確率の公式とベイズの定理の関係を、もっとも基本的な棒グラフで可視化します。事前確率→事後確率の更新が、視覚的に一目で把握できます。

import numpy as np
import matplotlib.pyplot as plt

# 工場のデータ
factories = ['Factory A', 'Factory B', 'Factory C']
production_share = np.array([0.50, 0.30, 0.20])  # 事前 P(A_i)
defect_rate = np.array([0.02, 0.03, 0.05])       # 尤度 P(D|A_i)
colors = ['steelblue', 'coral', 'green']

# 全確率の公式: P(D)
contributions = production_share * defect_rate
total_defect = contributions.sum()
print(f"P(D) = {total_defect:.4f}")

# ベイズの定理: P(A_i | D)
posterior = contributions / total_defect
for f, p in zip(factories, posterior):
    print(f"P({f} | D) = {p:.4f}")

fig, axes = plt.subplots(1, 3, figsize=(16, 5))

# (a) 全確率の公式の積み上げ分解
ax = axes[0]
bottom = 0
for i, contrib in enumerate(contributions):
    ax.bar('P(D)', contrib, bottom=bottom, color=colors[i],
           alpha=0.8, edgecolor='gray',
           label=f'{factories[i]}: {contrib:.3f}')
    ax.text(0, bottom + contrib / 2,
            f'{factories[i]}\n{contrib:.3f}',
            ha='center', va='center', fontsize=10, fontweight='bold')
    bottom += contrib
ax.axhline(total_defect, color='black', ls='--', lw=1.5)
ax.text(0.35, total_defect + 0.001,
        f'Total = {total_defect:.3f}', fontsize=12, fontweight='bold')
ax.set_ylabel('Probability', fontsize=12)
ax.set_title(r'Law of Total Probability'
             '\n' r'$P(D) = \sum_i P(D|A_i)P(A_i)$', fontsize=13)
ax.legend(fontsize=9, loc='upper right')
ax.set_ylim(0, 0.04)
ax.grid(True, alpha=0.3, axis='y')

# (b) 事前確率 vs 事後確率
ax = axes[1]
x = np.arange(3)
w = 0.35
b1 = ax.bar(x - w / 2, production_share, w, color='lightblue',
            edgecolor='gray', label='Prior P(Factory)')
b2 = ax.bar(x + w / 2, posterior, w, color='salmon',
            edgecolor='gray', label='Posterior P(Factory|D)')
ax.set_xticks(x)
ax.set_xticklabels(factories, fontsize=10)
ax.set_ylabel('Probability', fontsize=12)
ax.set_title("Prior vs Posterior\n(Bayes' Theorem)", fontsize=13)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3, axis='y')
for bar in list(b1) + list(b2):
    ax.text(bar.get_x() + bar.get_width() / 2,
            bar.get_height() + 0.01,
            f'{bar.get_height():.2f}', ha='center', fontsize=10)

# (c) 不良品率と寄与のトレードオフ
ax = axes[2]
rate_range = np.linspace(0.001, 0.10, 100)
for i, f in enumerate(factories):
    ax.plot(rate_range * 100,
            production_share[i] * rate_range * 100,
            color=colors[i], linewidth=2,
            label=f'{f} (share={production_share[i]:.0%})')
    ax.plot(defect_rate[i] * 100, contributions[i] * 100, 'o',
            color=colors[i], markersize=10,
            markeredgecolor='black', markeredgewidth=1.5)
ax.set_xlabel('Defect Rate (%)', fontsize=12)
ax.set_ylabel('Contribution to Total Defect (%)', fontsize=12)
ax.set_title('Contribution = Defect Rate × Production Share',
             fontsize=13)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('total_probability_factories.png', dpi=150,
            bbox_inches='tight')
plt.show()

このグラフからは、3つの重要な気づきが読み取れます。

  1. 左図(全確率の公式の分解): 全体不良品率2.9%が、工場ごとの寄与(0.010, 0.009, 0.010)に分解されています。工場Aと工場Cの寄与が同じ約1.0%なのは、Aが「低不良率×高生産」、Cが「高不良率×低生産」というトレードオフでバランスしているためです。
  2. 中央図(事前 vs 事後): 不良品が出たという条件付きでの工場分布(赤)は、生産量分布(青)から 歪んで います。工場B,Cが相対的に増え、工場Aが減る。「観測した結果が、原因の確率分布を再配分する」というベイズ更新の本質が一目でわかります。
  3. 右図(寄与曲線): 寄与の傾きは生産比率です。傾きが大きい工場ほど、同じ不良率の改善でも全体への効果が大きい。品質改善の優先順位を決める実務的な視点に直結します。

ここから、もう一段難しい応用としてナイーブベイズ分類器を実装します。

ナイーブベイズによるスパムフィルタ

スパム判定をPythonで実装します。簡単のため、ボキャブラリは6語の小規模なトイデータセットで動かします。

import numpy as np

# 訓練データ: (メール本文の単語リスト, ラベル)
# ラベル: 1=spam, 0=ham
train_data = [
    (['free', 'money', 'win', 'now'], 1),
    (['win', 'money', 'free', 'free'], 1),
    (['cheap', 'free', 'money'], 1),
    (['win', 'cheap', 'now'], 1),
    (['meeting', 'tomorrow', 'office'], 0),
    (['project', 'meeting', 'now'], 0),
    (['office', 'project', 'tomorrow'], 0),
    (['meeting', 'project', 'office', 'tomorrow'], 0),
]

vocab = sorted({w for words, _ in train_data for w in words})
word2idx = {w: i for i, w in enumerate(vocab)}
V = len(vocab)
print(f"Vocabulary ({V} words): {vocab}")


def fit_naive_bayes(data, V, alpha=1.0):
    """ラプラススムージング付き多項ナイーブベイズの学習."""
    class_counts = np.zeros(2)             # クラスの出現回数
    word_counts = np.zeros((2, V))         # クラスごとの単語頻度
    for words, label in data:
        class_counts[label] += 1
        for w in words:
            word_counts[label, word2idx[w]] += 1
    # 事前確率 P(C)
    log_prior = np.log(class_counts / class_counts.sum())
    # 尤度 P(w|C): ラプラススムージング
    word_totals = word_counts.sum(axis=1, keepdims=True)
    log_likelihood = np.log((word_counts + alpha) /
                            (word_totals + alpha * V))
    return log_prior, log_likelihood


log_prior, log_likelihood = fit_naive_bayes(train_data, V)
print(f"\nP(spam) = {np.exp(log_prior[1]):.3f}")
print(f"P(ham)  = {np.exp(log_prior[0]):.3f}")


def predict(words, log_prior, log_likelihood):
    """対数事後確率と予測クラスを返す."""
    log_post = log_prior.copy()
    for w in words:
        if w in word2idx:
            log_post += log_likelihood[:, word2idx[w]]
    # 正規化 (logsumexpトリックで underflow を避ける)
    log_post -= log_post.max()
    post = np.exp(log_post)
    post /= post.sum()
    return post


# 推論テスト
test_emails = [
    ['free', 'money'],
    ['meeting', 'project'],
    ['free', 'meeting'],   # 混じった例
    ['cheap', 'win', 'now', 'tomorrow'],
]
for email in test_emails:
    post = predict(email, log_prior, log_likelihood)
    label = 'SPAM' if post[1] > 0.5 else 'HAM'
    print(f"{email!s:50s} -> P(spam)={post[1]:.3f} [{label}]")

推論テストの結果は次のように出ます。

  • ['free','money'] → P(spam) ≈ 0.95 → SPAM。両単語ともスパム側で高頻度なので、当然の判定です。
  • ['meeting','project'] → P(spam) ≈ 0.04 → HAM。ハム側で典型的な単語ですから、強い HAM 判定。
  • ['free','meeting'] → 中間的だがハム寄り。スパム単語1つ vs ハム単語1つで対立しますが、事前確率は50:50なので、わずかな尤度差で結果が変わります。
  • ['cheap','win','now','tomorrow'] → 多くのスパム単語があるためスパム寄り。

ここで重要なのは、分母の正規化に 全確率の公式 がそのまま使われている点です。

$$ P(\text{spam}\mid \mathbf{w}) = \frac{P(\mathbf{w}\mid \text{spam})P(\text{spam})}{P(\mathbf{w}\mid \text{spam})P(\text{spam}) + P(\mathbf{w}\mid \text{ham})P(\text{ham})} $$

ナイーブベイズの「ナイーブ」たる所以は「単語が条件付きで独立」と仮定する点で、$P(\mathbf{w}\mid C) = \prod_i P(w_i\mid C)$ と分解しています。この独立性仮定は現実には成り立ちませんが、テキスト分類では驚くほどうまく機能することが経験的に知られています。

連続版: ベイズ更新の可視化

最後に、ベイズ更新の動的な様子を可視化します。観測データが1つずつ追加されるにつれて、事後分布の形が変わっていくアニメ的な静止画です。例として、コインの表が出る確率 $\theta$ をベイズ的に推定します(事前: 一様分布、尤度: ベルヌーイ)。

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(0)
true_theta = 0.7
n_total = 200
data = np.random.binomial(1, true_theta, n_total)

theta_grid = np.linspace(0, 1, 500)
prior = np.ones_like(theta_grid)  # 一様 Beta(1,1)

snapshots = [0, 1, 2, 5, 10, 30, 100, 200]
fig, axes = plt.subplots(2, 4, figsize=(15, 7))
axes = axes.flatten()

for ax, n in zip(axes, snapshots):
    # 共役性で事後 = Beta(1 + #heads, 1 + #tails)
    heads = data[:n].sum()
    tails = n - heads
    post = stats.beta.pdf(theta_grid, 1 + heads, 1 + tails)
    ax.fill_between(theta_grid, post, alpha=0.4, color='steelblue')
    ax.plot(theta_grid, post, color='steelblue', linewidth=2,
            label=f'Posterior (n={n})')
    ax.axvline(true_theta, color='red', linestyle='--',
               linewidth=1.5, label=f'True θ={true_theta}')
    if n == 0:
        ax.plot(theta_grid, prior, color='gray', linewidth=1.5,
                label='Prior (Uniform)')
    ax.set_xlim(0, 1)
    ax.set_title(f'n = {n} (heads={heads}, tails={tails})',
                 fontsize=11)
    ax.set_xlabel(r'$\theta$', fontsize=11)
    ax.set_ylabel('Density', fontsize=10)
    ax.legend(fontsize=9, loc='upper left')
    ax.grid(True, alpha=0.3)

plt.suptitle("Bayesian Updating of P(θ | data)", fontsize=14,
             y=1.02)
plt.tight_layout()
plt.savefig('bayesian_updating.png', dpi=150, bbox_inches='tight')
plt.show()

この8枚の事後分布を時系列で並べたグラフからは、ベイズ推論の本質が見て取れます。

  1. $n=0$ 時点: 事前分布は一様(均等な無情報事前)。$\theta$ について何も知らない状態です。
  2. $n=1,2$ 時点: 1〜2回のコイン投げで形がついて、観測結果に合わせて若干非対称になります。データが少ないため幅は依然広く、不確実性が大きい状態です。
  3. $n=10,30$ 時点: 中央値が真値 $\theta=0.7$ 付近に集中し始め、分布の幅が急速に狭まります。
  4. $n=200$ 時点: 分布は真値の周辺に鋭く集中。標準誤差は $1/\sqrt{n}$ オーダーで縮みます。

この振る舞いは「データが増えるほど事後分布は真値に収束する」というベイズ統計学の基本性質(consistency)の可視化です。各時点の事後分布の 正規化定数 は全確率の公式で計算されている、と思って改めて式を眺めると、両者が一体になって動いていることが実感できます。

ここで使われている事前分布 Beta(1,1) は一様分布で、「何も知らない」状態を表します。もし先験的な知識があれば、たとえばコインが公平に近いと信じるなら Beta(10,10) のような尖った事前を選びます。事前を強くするほど、少ないデータでは事前の影響が残り、データが増えるにつれて尤度が勝って事後分布が真値へ収束していく——これがベイズ統計の動的バランスです。本記事ではコインを例にしましたが、ガウス分布の平均、ポアソン過程の到着率、ロジスティック回帰のパラメータなど、ありとあらゆる場面で同じ更新原理が再現されます。

連続版の応用として、もう一つ重要な「混合分布」も触れておきます。

連続版 — 混合分布と全期待値・全分散の定理

連続版の全確率の公式

離散の場合は和でしたが、$Y$ が連続確率変数のときは積分に置き換わります。連続確率変数 $X$ の周辺密度は、

$$ \begin{equation} f_X(x) = \int_{-\infty}^{\infty} f_{X\mid Y}(x\mid y)\,f_Y(y)\,dy \end{equation} $$

これは「$Y$ について同時密度を積分消去する(周辺化)」操作にほかなりません。全確率の公式の離散和を、滑らかに積分に置き換えただけです。

混合分布

連続版の代表的応用が 混合分布 (mixture distribution) です。クラスター $Z$ が $K$ 個あり、$P(Z=k) = \pi_k$、各クラスター内のデータが $f_k(x)$ に従うとすると、全体の周辺密度は、

$$ f(x) = \sum_{k=1}^{K} \pi_k f_k(x) $$

混合正規分布なら $f_k(x) = \mathcal N(x\mid \mu_k, \sigma_k^2)$。これはちょうど全確率の公式 $f(x) = \sum_k f(x\mid Z=k)P(Z=k)$ で、$Z$ を周辺化した結果と等しいものです。

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

weights = np.array([0.40, 0.35, 0.25])
means = np.array([-2.0, 1.0, 4.0])
stds = np.array([0.8, 1.2, 0.6])
x = np.linspace(-6, 8, 500)

mixture = np.zeros_like(x)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# (a) 混合分布の分解
ax = axes[0]
colors_mix = ['steelblue', 'coral', 'green']
for i, (w, mu, sd) in enumerate(zip(weights, means, stds)):
    comp = w * stats.norm.pdf(x, mu, sd)
    mixture += comp
    ax.fill_between(x, comp, alpha=0.3, color=colors_mix[i])
    ax.plot(x, comp, color=colors_mix[i], lw=1.5,
            label=rf'$\pi_{i+1}={w}, \mu_{i+1}={mu}, \sigma_{i+1}={sd}$')
ax.plot(x, mixture, 'k-', lw=2.5, label='Mixture $f(x)$')
ax.set_xlabel('x', fontsize=12); ax.set_ylabel('Density', fontsize=12)
ax.set_title('Law of Total Probability (Continuous)\n'
             r'$f(x)=\sum_k \pi_k \mathcal{N}(x|\mu_k,\sigma_k^2)$',
             fontsize=12)
ax.legend(fontsize=9); ax.grid(True, alpha=0.3)

# (b) 責任 (responsibility) = 事後 P(Z=k | x)
ax = axes[1]
for i, (w, mu, sd) in enumerate(zip(weights, means, stds)):
    comp = w * stats.norm.pdf(x, mu, sd)
    resp = comp / np.maximum(mixture, 1e-10)
    ax.plot(x, resp, lw=2, color=colors_mix[i],
            label=rf'$P(Z={i+1}|x)$')
ax.set_xlabel('x', fontsize=12)
ax.set_ylabel('Posterior P(Component | x)', fontsize=12)
ax.set_title("Component Responsibility\n(Bayes' Theorem)",
             fontsize=12)
ax.legend(fontsize=10); ax.grid(True, alpha=0.3)
ax.set_ylim(-0.05, 1.05)

plt.tight_layout()
plt.savefig('mixture_total_probability.png', dpi=150,
            bbox_inches='tight')
plt.show()

この混合分布の図から、全確率の公式・ベイズの定理の連続版が機能するさまを読み取れます。

  1. 左図(混合分布の分解): 黒線が全体密度 $f(x)$、色付き領域が各コンポーネントの重み付き密度 $\pi_k f_k(x)$。全確率の公式そのもので、3つのコンポーネントの「積み上げ」が全体の密度を作っています。
  2. 右図(コンポーネントの責任): データ点 $x$ が各コンポーネントから生成された事後確率 $P(Z=k\mid x) = \pi_k f_k(x) / f(x)$ がベイズの定理から計算されています。$x=-2$ 付近ではコンポーネント1が責任のほぼ全てを占め、コンポーネント間の境界では責任が混合します。この計算がEMアルゴリズムのE-ステップの本質です。

全期待値の定理

全確率の公式を期待値版に拡張したものが、全期待値の定理 (law of total expectation) です。

$$ \begin{equation} E[X] = E\bigl[E[X\mid Y]\bigr] = \sum_y E[X\mid Y=y]\,P(Y=y) \end{equation} $$

全分散の定理も同様にあります。

$$ \mathrm{Var}(X) = E\bigl[\mathrm{Var}(X\mid Y)\bigr] + \mathrm{Var}\bigl(E[X\mid Y]\bigr) $$

これは「全分散は、各条件内の分散の平均 + 条件ごとの平均のばらつき」と読めます。階層モデルやベイズ統計学では基本道具で、グループ間変動とグループ内変動を分離するときに頻出します。たとえば「複数の学校で学力テストを実施したときの全体分散」は、「各学校内のばらつきの平均」と「学校間の平均得点のばらつき」に分解できる、というあの分散分析(ANOVA)の基礎です。

混合分布による連続版の全確率と、全分散の定理による分散の2分解

左は3つの正規分布を重み 0.5 / 0.3 / 0.2 で混ぜた混合分布です。灰色の塗りつぶし(混合分布)と赤の破線(各成分の重み付き和)が完全に一致しており、混合分布が連続版の全確率の公式そのものであることが目で確認できます。右は全分散の定理の2項を実際に計算したもので、成分内のばらつき $E[\mathrm{Var}(X\mid Z)] = 0.482$ より、成分間の平均のばらつき $\mathrm{Var}(E[X\mid Z]) = 3.813$ のほうが圧倒的に大きい。この分布の分散 4.29 のほとんどは「どの成分に属するか」で説明できる、という読み方になります。

周辺尤度とベイズモデル選択

連続版の全確率の公式は、ベイズ統計におけるモデル選択の基盤にもなっています。モデル $M$ のパラメータ $\theta$ に対する事前分布 $p(\theta\mid M)$、尤度 $p(\mathcal D\mid \theta, M)$ があるとき、データ $\mathcal D$ がモデル $M$ の下で観測される確率は、

$$ p(\mathcal D\mid M) = \int p(\mathcal D\mid \theta, M)\,p(\theta\mid M)\,d\theta $$

この $p(\mathcal D\mid M)$ を 周辺尤度(marginal likelihood)あるいは エビデンス と呼びます。複数のモデル $M_1, M_2$ を比べたいときは、両者の周辺尤度の比 $p(\mathcal D\mid M_1)/p(\mathcal D\mid M_2)$ をベイズファクターとして使います。これがベイズモデル選択の中核で、その計算には全確率の公式の連続版による $\theta$ の周辺化が不可避なのです。

まとめ

本記事では、確率推論の双子の基本則である 全確率の公式ベイズの定理 を、両者の関係を中心に体系的に解説しました。

  • 全確率の公式 $P(B) = \sum_i P(B\mid A_i)P(A_i)$ は、複雑な事象の確率を場合分けして条件付き確率の重み付き和に分解する手続き
  • ベイズの定理 $P(A\mid B) = P(B\mid A)P(A)/P(B)$ は、観測データから仮説を逆方向に更新する手続き
  • 両者は表裏一体で、ベイズの定理の分母 $P(B)$ は必ず全確率の公式で組み立てる
  • モンティ・ホール問題(変えるべき)、医療検査(陽性でも約2%)、スパムフィルタ(ナイーブベイズ)はすべて同じ枠組みで解ける
  • 連続版 では和が積分に置き換わり、混合分布は連続版の全確率の公式そのもの
  • 全期待値・全分散の定理 は階層モデルやベイズ統計の基本道具

全確率の公式とベイズの定理の使い分け早見表

最後に両者の使い分けを1枚にまとめました。「結果が起きる確率を知りたい」なら全確率の公式、「観測した結果の原因を知りたい」ならベイズの定理——判断はこの一問で足ります。必要な材料が同じである点に注目してください。ベイズの定理は新しい情報を要求しません。同じ材料の使い方を変えているだけで、しかもその過程で全確率の公式を必ず1回通ります。実務では「まず合成して分母を作り、次に分析する」という2段構えで使うことになります。

ベイズの定理が威力を発揮するのは、「データが追加されるたびに事後分布を再計算する」という 逐次更新 の場面です。事前 → 事後 → 次の更新の事前 → さらなる事後… と再帰的に推論を進められる構造が、機械学習・信号処理・統計推測の至るところに現れます。

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