ベイズ更新をやってみた!

3月の末にベイズ推定の勉強会に参加してきました!
math-unknown.connpass.com
この勉強会では単に講師の話を聞くだけではなく,みんなでワイワイディスカッションしながら進めるような形式で,グループ内の誰かが疑問に思ったことを後で調べることでより理解が深まったように思います.
そして講師の方の説明の流暢さに脱帽でした!

その中でもベイズ更新の例としてオオカミ少年の例が興味深いと思いました.勉強会の案内のところに次のリンクが貼ってあったので,共有しておきます.
okandayo.hatenablog.com
ベイズ更新を使ってオオカミ少年の例をシミュレーションしてみようと思いましたが,なかなか時間がなく出来ませんでした.ようやく取り掛かることが出来たのでちょこっとやってみたわけです.

問題設定

次のような風に問題文を作ってみます.「オオカミ少年」のお話は昔NHKの番組で見たことがある程度なのでうろ覚えですが,少年が嘘をついて「オオカミが来たぞ!」と叫んでいるうちに村人が誰も少年を信用しなくなってしまい,本当にオオカミが来た時に村人が食べられてしまった話だったと思います.

問題文;オオカミ少年
ある村では嘘つきは75%の確率で嘘をつき,正直者は85%の確率で本当のことを証言することが知られている.
この村のある少年は事あるごとに「オオカミが来たぞ!」と叫んでいるが,本当に狼が来るときと来ない時があるようだ.この少年は嘘をついている,もしくは時々間違えるようである.この少年が100回叫んだ結果から,この少年は正直者か嘘つきかを答えよ.

問題文から仮定と各値を書き出す

この問題文から,次の様のような仮定を置きます.

  • H_{1}:少年は嘘つき
  • H_{2}:少年は正直者

「オオカミが来たぞ!」と叫ぶイベントに対して,本当にオオカミが来る事象と来ない事象があります.これを次のように置きます.

  • A:少年は嘘をつく(「オオカミが来たぞ!」と叫んだときにオオカミが来ない)
  • \bar { A } :少年は本当のことを言う(「オオカミが来たぞ!」と叫んだときにオオカミが来る)

A\bar { A } は「オオカミが来たぞ!」と叫んで来ないときと実際に来たときに相当します.これらには次の図のような関係があります.
]

さて,次に問題文からそれぞれの値を次のように置きます.

  • P\left( A|{ H_{ 1 } } \right) =0.15:ある村で嘘つきが本当の証言をする確率
    • →嘘つきが「オオカミが来たぞ!」と叫んで,オオカミが来る確率
  • P\left( A|{ H_{ 2 } } \right) =0.75:ある村で正直者が本当の証言をつく確率
    • →正直者が「オオカミが来たぞ!」と叫んでオオカミが来る確率
  • P\left( \overline { A } |{ H_{ 1 } } \right)=0.85 :ある村で嘘つきが嘘の証言をする確率
    • →嘘つきが「オオカミが来たぞ!」と叫んでもオオカミが来ない確率
  • P\left( \overline { A } |{ H_{ 2 } } \right) =0.25:ある村で正直な人が間違えて嘘の証言をする確率
    • →正直者が間違えて「オオカミが来たぞ!」と叫んでオオカミが来ない確率

これを表にするとこんな感じです.

  オオカミが来る A オオカミが来ない  \bar { A }
嘘つき H_{1} 0.15 0.85
正直 H_{2} 0.75 0.25

更新則を求める

さて,次にベイズの定理と全確率の公式から

  1. 「オオカミが来たぞ!」と叫んで本当に狼が来た場合,少年が嘘つきである確率
  2. 「オオカミが来たぞ!」と叫んで狼が来なかった場合,少年が嘘つきである確率

をそれぞれ求めます.ベイズの定理と全確率は下記を参照ください.

「オオカミが来たぞ!」と叫んで本当に狼が来た場合,少年が嘘つきである確率


\begin{eqnarray*} P\left( { H_{ 1 } }|{ A } \right)  & = & \frac { P\left( { A }|{ H_{ 1 } } \right) P\left( { H_{ 1 } } \right)  }{ P\left( { A } \right)  }  \\  & = & \frac { P\left( { A }|{ H_{ 1 } } \right) P\left( { H_{ 1 } } \right)  }{ \sum _{ H }^{  }{ P\left( { A }|{ H } \right) P\left( { H } \right)  }  }  \\  & = & \frac { P\left( { A }|{ H_{ 1 } } \right) P\left( { H_{ 1 } } \right)  }{ P\left( { A }|{ H_{ 1 } } \right) P\left( { H_{ 1 } } \right) +P\left( { A }|{ H_{ 2 } } \right) P\left( { H_{ 2 } } \right)  }  \end{eqnarray*}

「オオカミが来たぞ!」と叫んで狼が来なかった場合,少年が嘘つきである確率


\begin{eqnarray*} P({ H_{ 2 } }|\overline { A } ) & = & \frac { P({ { \overline { A }  } }|{ H_{ 2 } })P\left( { H_{ 2 } } \right)  }{ P({ { \overline { A }  } }) }  \\  & = & \frac { P({ { \overline { A }  } }|{ H_{ 2 } })P({ H_{ 2 } }) }{ \sum _{ H }^{  }{ P({ { \overline { A }  } }|{ H })P\left( { H } \right)  }  }  \\  & = & \frac { P({ { \overline { A }  } }|{ H_{ 2 } })P\left( { H_{ 2 } } \right)  }{ P({ { \overline { A }  } }|{ H_{ 1 } })P\left( { H_{ 1 } } \right) +P({ { \overline { A }  } }|{ H_{ 2 } })P\left( { H_{ 2 } } \right)  }  \end{eqnarray*}

シミュレーション

次に実際にシミュレーションしてみます.Pythonでこんな感じに書きました.

import numpy as np
import matplotlib.pyplot as plt

# 確率の設定
p_AH1 = 0.15 # 嘘つきがが嘘をついてオオカミが来ない確率
p_AH2 = 0.75 # 正直者が本当のことを言ってオオカミが来る確率
p_barAH1 = 0.85 # 嘘つきが間違えて正しいことを言う確率
p_barAH2 = 0.25 # 正直者が間違える確率

# 嘘つきである確率の初期値
p_l = [0.5]

# ループ計算
for i in range(99):
    rand = np.random.random()

    #「オオカミが来たぞ!」と叫んだときに狼が来る
    if rand >0.5:
        p_l.append(p_l[i]*p_barAH1/(p_barAH1*p_l[i]+p_barAH2*(1-p_l[i])))

    #「オオカミが来たぞ!」と叫んだときに狼が来ない
    else:
        p_l.append(p_l[i]*p_AH1/(p_AH1*p_l[i]+p_AH2*(1-p_l[i])))

# 描画        
plt.plot(range(100),p_l)
plt.xlabel('times')
plt.ylabel('H1')
plt.grid()
plt.show()
シミュレーション結果

狼が来る確率を0.4.0.5,0.6とそれぞれ変化させてみたのが下の図です.(ちなみにx軸のレンジが100だと見づらいので80にしています)

今回は問題設定上,正直者と判定されやすいのでこうなりました.
ただし,狼が来る確率を0.4の場合には毎回結果が異なり,正直者と判定される場合や嘘つきと判定される場合に分かれました.その様子を表したのが下の図です.

というわけで今日はこんな感じで.