統計学入門④ 条件付確率とベイズの定理

f:id:monozukuri-bu:20190520215606j:plain

こんにちは。前回に引き続きふじもんです。
この間子猫につけられた傷も癒えてきたところです。

さて!今回は、前回紹介した確率の計算から発展して、
・条件付き確率
・乗法定理
ベイズの定理

を紹介します!
そして最後にこれらの式をPythonで実装し、問題を解いてみたいと思います!!

条件付き確率

まず最初に条件付き確率です。
条件付き確率とは、 事象Aが起こった条件下において事象Bが起こる確率のこと。
条件付き確率は、以下の式で求められます。


P(B|A) = \frac{P(A \cap B)}{P(A)}

上記の式は分母が「Aが起こる確率」、分子が「AとBが同時に起こる確率」を表しており、
Aが起こる確率の中で、さらにAとBが起こる確率が求められる式となっています。

例えば、袋Xと袋Yの2種類の袋があり、
XとYの袋にはそれぞれ赤玉と白玉がランダムに入っているとしてます。
そのうちXの袋を選ぶ事象をA、赤玉を引く事象をBとした場合、
袋Xを選んだ時(事象A)に赤玉を引く(事象B)確率を求める、といったことができます。

乗法定理

さて 、お次は乗法定理です。 乗法定理は以下の式で求められます。


{P(A \cap B)}=P(B|A) \times P(A)


おや?さっきの式とちょっと変わっただけじゃない?
そうです、パッとみて気付く人も多いかと思いますが、乗法定理の式は条件付き確率の式を変形したものです。
じゃあ、条件付き確率乗法定理って何が違うの??というと、
条件付き確率はAが起こった条件下でBが起こる確率に対し、
乗法定理はAとBが同時に起こる確率を意味します。

具体的にいうと、条件付き確率の時は 袋Xを選んだ時に赤玉を引く確率
つまりもう袋Xが選ばれている状態で赤玉を引く確率を求める場合に使います。
それに対し、乗法定理では 袋Xを選び、且つ赤玉を引く確率
まだXが選ばれているかわからない状態で、袋Xを選ぶ確率を考えた上で赤玉を引く確率を求める場合に使います。
なので、条件付き確率は袋Xを選んだ確率P(A)が分母にあり、乗法定理では分子にあるのです。

前提条件がちょっと異なっているのが、条件付き確率と乗法定理の違いですね。

ベイズの定理

最後にベイズの定理です。
ベイズの定理は以下の式で求められます。


{P(A|B) = \frac{P(B|A) \times P(A)}{P(B)}}


あれ??これよくよく見ると条件付き確率がちょっと変わっただけじゃない…?

そうです、ベイズの定理も条件付き確率を変形させたものになります。
ただしベイズの定理は、条件付き確率と少し違うところがあります。
それは時間の流れです。

条件付き確率の時に例えた袋の話ですと、
条件付き確率P(B|A)は、袋Xを選んだ時(事象A)に赤玉を引く(事象B)確率を求める式でしたが、
ベイズの定理P(A|B)は、引いた玉が赤玉のとき(事象B)の袋がXである(事象A)確率を求めることになります。

結果はこうだったけど、なんで???と結果から原因を求められるのがベイズの定理です。

Pythonで実装

さて今回も長々と説明してしまいましたが、上記のそれぞれの式をPythonを使って実装してみます!

例題

袋Xと袋Yの2種類の袋があり、次のように玉が入っています。
X:赤玉が3個、白玉が5個
Y:赤玉が1個、白玉が3個
なお、袋Xと袋Yを選ぶ確率は等しいとします。

1.袋Xを選んだ時に赤玉を引く確率は?(条件付き確率)
2.袋Xを選び、且つ、赤玉を引く確率は?(乗法定理)
3.引いた赤玉が袋Xから取り出された確率?(ベイズの定理)


<実装>

# 定義
bag = 2 # 袋の総数
bag_x = 1 # 袋Xの数
bag_y = 1 # 袋Yの数

ball_in_bag_x = [3, 5] # 袋Xの中身(赤玉が3個、白玉が5個)
ball_in_bag_y = [1, 3] # 袋Yの中身(赤玉が1個、白玉が3個)


# 条件付き確率
def conditional_probability(bag, bag_sum, ball_in_bag):
    ans = ball_in_bag[0] / sum(ball_in_bag)
    return ans

# 乗法定理
def multiplication_theorem(bag, bag_sum, ball_in_bag):
    ans = (ball_in_bag[0] / sum(ball_in_bag)) * (bag / bag_sum)
    return ans

# ベイズの定理
def bayesian_theorem(bag1, bag2, bag_sum, ball_in_bag1, ball_in_bag2):
    p_a_cap_b = multiplication_theorem(bag1, bag_sum, ball_in_bag1)  # 乗法定理を活用
    pb = ((bag1 / bag_sum) * (ball_in_bag1[0]/sum(ball_in_bag1))) \  # 袋Xから赤玉を引く確率
        + ((bag2 / bag_sum) * (ball_in_bag2[0]/sum(ball_in_bag2)))   # 袋Yから赤玉を引く確率
    ans = p_a_cap_b / pb
    return(ans)


cp = conditional_probability(bag_x, bag, ball_in_bag_x)
mt = multiplication_theorem(bag_x, bag, ball_in_bag_x)
bt = bayesian_theorem(bag_x, bag_y, bag, ball_in_bag_x, ball_in_bag_y)

print("1.の答え:" + str(cp*100) + "%")
print("2.の答え:" + str(mt*100) + "%")
print("3.の答え:" + str(bt*100) + "%")

<実行結果>

1.の答え:37.5%
2.の答え:18.75%
3.の答え:60.0%

それぞれを計算するための式は、こんな風に書けます。

cp = conditional_probability(bag_x, bag, ball_in_bag_x)は、
袋Xを選んでいること前提のため、袋Xの情報を渡してあげています。

mt = multiplication_theorem(bag_x, bag, ball_in_bag_x)は、
袋Xを選ぶ確率も考慮しなければならないため、袋Xの情報に加え袋の総数も渡してあげる必要があります。

bt = bayesian_theorem(bag_x, bag_y, bag, ball_in_bag_x, ball_in_bag_y)は、
ベイズの定理の分母P(B)で、袋Xから赤玉を引く確率と、袋Yから赤玉を引く確率それぞれ考慮し
赤玉を引く確率を計算するため、袋Yの情報も渡してあげています。
さらにベイズの定理の分子は乗法定理の式のため、しれっと乗法定理もここで再利用できちゃいます。


それぞれの式を見るとちょっと抵抗を感じてしまう方もいると思いますが、
コードに書き起こしてみると簡単に書けるので、
結構簡単なことなんだなーって印象を受けますね!

まとめ

今回は、前回の確率の計算からちょっと発展したものを紹介しました!
慣れない人には一見取っつきづらそうな計算式ですが、
コードに起こしてみると決して難しいことじゃなさそうですね。
さらにベイズの定理の結果から原因を導き出す考えは、統計や分析では頻出する重要な考えですので、
基礎からしっかりマスターしたいところです!
しかも一度コードにしてしまえば、引数を変えるだけであっという間にいろんなパターンの計算ができるのでとても便利。
今後もいろいろなことをコードに起こすことを実践してみたいです!