「続・わかりやすい パターン認識」
第2章 事前確率と事後確率>2.1 事後確率の計算>[1] コインを1度だけ投げる場合 (p.25)

を、プログラムで計算してみる。


例題 2.1 (意訳)箱の中に3種類のコインが入っていて、取り出して投げたら表が出た。
どのコインだったか?

3種類のコインは箱の中にそれぞれ10%, 40%, 50%の割合で含まれている。 またコインは偏っていて、投げた時に表が出る確率がコインの種類によってそれぞれ 80%, 60%, 30%となっている:

  コイン1 () コイン2 () コイン3 ()
含有率( 0.1 0.4 0.5
表が出る率( 0.8 0.6 0.3

コード

# coin_probability1.rb
def main
  # πi: それぞれのコインが箱の中にどのような割合で混ざっているか(事前確率)
  pi = [0.1, 0.4, 0.5]

  # θi: それぞれのコインを投げた時に表が出る確率
  theta = [0.8, 0.6, 0.3]

  calc_posterior_probability(pi, theta).each_with_index do |post_prob, i|
    puts "P(omega_#{i+1} | H) = #{post_prob}"
  end
end

# 箱の中から取り出したコインを投げて表が出た時に、
# 取り出したコインがどれだったか、それぞれのコインの確率を求める
# _pi_ :: それぞれのコインが箱の中にどのような割合で混ざっているか、の配列
# _theta_ :: それぞれのコインを投げた時に表が出る確率、の配列
def calc_posterior_probability(pi, theta)
  c = pi.size
  # P(H): コインの表が出る全体の確率を求める
  head_prob = sigma(0...c) do |i|
    pi[i] * theta[i]
  end

  # 表が出たという情報から、それぞれのコインが取り出された確率を求める
  (0...c).map do |i|
    pi[i] * theta[i] / head_prob
  end
end

# Rangeに対してブロックを呼び出し、その結果の和を返す:∑
def sigma(range, &block)
  range.map do |i|
    block.call(i)
  end.inject(:+)
end

main

# P(omega_1 | H) = 0.17021276595744686
# P(omega_2 | H) = 0.5106382978723404
# P(omega_3 | H) = 0.3191489361702128

投げて表が出たという情報を得て、確率がどう変化したか?

  コイン1 () コイン2 () コイン3 ()
取り出した段階   0.1 0.4 0.5
投げて表が出た後  0.170… 0.510… 0.319…


事前の情報として箱の中には各コインが10%, 40%, 50%の割合で含まれているということなので、 取り出したのがどのコインなのかはその割合と推測するが、 投げて表が出たという結果から、表の出やすいコイン1と2であった可能性が増えて、 逆に表の出にくいコイン3だった可能性が下がる。

chart