CodeIQ MAGAZINECodeIQ MAGAZINE

池澤あやかとプログラミングで学ぼう!機械学習のための数学講座【ベイズの定理編】

2017.03.27 Category:【連載】池澤あやか☆勉強部 Tag: , , ,

  • 117
  • このエントリーをはてなブックマークに追加

今なにかと話題の機械学習。いざ始めようと思うと数字や数式、グラフのオンパレード…。数学が苦手な方にとってはなかなかハードルが高いのが現状です。そんな数学が苦手な皆さま、これを期に復習したいと思っている皆さま、一緒に勉強していきましょう! by 池澤あやか

機械学習のための数学ゼミ第二回はベイズの定理編!

ということで、第一回の確率分布に続き、第二回はベイズの定理を学びます。

まずは今回の登場人物をご紹介します!

<登場人物>


池澤あやか
タレントときどきエンジニア。数学は苦手だけど、機械学習入門したい。


増井雄一郎
株式会社トレタのえらいエンジニア。本人曰く、プログラムは書けるけど数学をまともに勉強したことがない。


梅崎先生
今回数学を教えてくれる先生。社会人のための数学教室「すうがくぶんか」の講師。

機械学習での大切な概念「ベイズの定理」を学ぶ!


前回は確率・統計の基礎の基礎、二項分布と多項分布について学びました。今日は『ベイズの定理』を学んでいきます。機械学習においてとても大事になってくる概念なので、しっかり覚えておいてください」


「前回もなかなか息切れものでしたが、頑張ります(涙)」


「では端的に説明しますね(笑)。ズバリ、ベイズの定理とは以下のような公式のことです」


「ヒーーッ!!!!公式!!!(涙)。でもこの記号たち、機械学習勉強してて出てきた気がしますね…」


「P(X)はXが起こる確率、P(Y)はYが起こる確率、P(Y|X)は、Xが起こった上でYが起こる確率という意味です」


Xをコーヒーを買った人、Yをクッキーを買った人で例えると、P(Y|X)はコーヒーを買った人の中でクッキーを買った人の割合ということになりますね」


「上の公式は、こういう式にも変形できます」


「P(Y|X)P(X)というのは、P(X)は全体のなかでXが起こる確率、P(Y|X)は、Xが起こった上でYが起こる確率で、掛け合わせるとP(X∩Y)つまり、XかつYが起こる確率ということになります。下のベン図でいうとこの緑色のZの部分のことですね。逆もまたしかりで、P(X|Y)P(Y)もこの緑色の部分のことになります。意外と簡単じゃないですか?」


「Xをコーヒー、Yをクッキーで例えると、コーヒーを買ってクッキーを買った人の確率と、クッキーを買ってコーヒーを買った人の確率が同じってことですね」


「そうなんです!ベイズの定理の問題を解くときは、何がXで何がYにあたるかをうまく設定することが重要です」


「なるほど」


「では、ベイズの定理を理解するために、ここでは例えば次のような問題を考えてみましょう。まずは単純に計算で求めてみてください」

【問題】あるお店で、コーヒーを買った人の中でクッキーを買った人の割合が50%でした。来客者全体でみてみると、コーヒーを買った人の割合が70%、クッキーを買った人の割合が60%です。では、クッキーを買った人の中でコーヒーを買った人の割合はいくらになるでしょうか。


「先程のように、ベン図にまとめてみると分かりやすいかもしれませんね」


「こういうベン図になりそうなので、ベイズの定理にもとづいて以下のように計算すると…」


「ということは約58.3%ってことですかね?」


「正解です!」

ベイズの定理をプログラムにしてみよう!


「それでは、先程の問題をプログラムに落とし込んでみましょう」


「はい!!公式を書き下しただけですが、このようなプログラムになるかと思います」

x = 0.7 # コーヒーを買った人の割合
y = 0.6 # クッキーを買った人の割合
yx = 0.5 # コーヒーを買った中でクッキーを買った人の割合

def bayes(x, y, yx):
    return yx * x / y

print bayes(x, y, yx)


「正解です。それでは同じプログラムを利用して以下の問題を解いてみてください」

【問題】箱Aには白玉4個と赤玉1個、箱Bには白玉1個と赤玉9個が入っているとします。1/2ずつの確率でどちらかの箱を選んで中身をひとつとった時、白玉が出てきました。この時、どちらの箱からとった可能性が高いでしょうか。


「複雑に見えるかもしれませんが、こういった問題ではまず、ベイズの定理の公式でいうと何がXで何がYとなるかを考えてみます。」

「ここでは、Xとしては『箱Aを選んだ』か『箱Bを選んだ』かの二通りを考えて、Yとしては『赤いボールをとった』か『白いボールをとった』かの二通りを考えるってことですか?」


「そうですね。さっきはXとしてコーヒーを買ったか買わないかの二通り、クッキーを買ったか買わないかの二通りです。そして、コーヒーを買ったうちでクッキーを買った人の割合をP(X|Y)で表しました。今回も『箱Aを選んだ上で赤いボールをとった確率』とか『赤いボールを取った時に箱Aを選んでいた確率』を同じようにP(X|Y)とかP(Y|X)と表せることに注意してください」


「イメージしずらいのでわかりやすくベン図を書こうと思います。箱Aと赤、箱Aと白、箱Bと赤、箱Bと白で、全部で4つベン図が書けますね。この交わっている部分の確率がどれが一番高いかを求めるってことですか?」


「はい。今回はとりだしたボールが白の場合のみ比較検討すればいいので、白いボールをとった二通りについて考えればよいというわけです」


「では先程のプログラムに当てはめると、箱Aから白が出た場合と箱Bから白が場合の確率を比べればよいということですね。実行してみます!」

x = 0.5 # 箱Aが選ばれる確率
y =  (4.0 / 5) * 0.5 + (1.0 / 10) * 0.5 # 白が出る確率
yx = 4.0 / 5 # 箱Aの中で白が出る確率

def bayes(x, y, yx):
    return yx * x / y

print bayes(x, y, yx)

>> 0.888888888889


x = 0.5 # 箱Aが選ばれる確率
y =  (4.0 / 5) * 0.5 + (1.0 / 10) * 0.5 # 白が出る確率
yx = 1.0 / 10 # 箱Bの中で白が出る確率

def bayes(x, y, yx):
    return yx * x / y

print bayes(x, y, yx)

>> 0.111111111111


「約0.9と約0.1なので白が出たら箱Aの確率が高いですね!」


「ここまで分かると、『ナイーブベイズ分類器』と呼ばれる機械学習のモデルを作ることができます。先ほどの問題のプログラムが書けていれば、半分くらい作ったも同然です」


ナイーブベイズ分類器はベイズの定理を利用したモデルだったんですね」


「はい。ナイーブベイズ分類器は迷惑メールフィルタにもよく使われているモデルなのですが、簡単に考えるとXが『迷惑メール』なのか『迷惑でない』のかで、Yがいろんな単語が入っているかどうかです。例えば『儲かる』という単語が入っているメールは迷惑メールっぽいということだとP(Y[儲かる]|X[迷惑])が大きいとか、『数学』という単語が入って入れば迷惑メールでなさそうということだとP(X[迷惑でない]|Y[数学])とかいう感じです」

ナイーブベイズ分類器の実際のプログラムを読んでみよう


「ナイーブベイズ分類器のプログラムを作ってみました。ちょっと一緒に読んでみましょう」


#coding:utf-8 import math from janome.tokenizer import Tokenizer import os class NaiveBayes(): def __init__(self):#学習結果を記録するobjectたち self.categories={}#{文書のカテゴリc:カテゴリcに属する文書の数} self.words={}#{文書のカテゴリc:{単語w:カテゴリcの文書全体での単語wの出現数}} self.smoothing=1#初見の単語の確率 self.texts={}#学習データ{カテゴリc:[カテゴリcの文書]} #与えられたディレクトリに入ったテキストファイルを学習データに加工する def pre_training(self, dir): self.texts={c.name:[] for c in os.scandir(dir) if c.is_dir()} for c in self.texts: file_list=[dir+'/'+c+'/'+f.name for f in os.scandir('train_data/'+c) if f.name[-3:]=='txt'] for file in file_list: f=open(file,'r') text=f.read() f.close() self.texts[c].append(text) #実際にテキストファイルの単語の数を数えて学習させる def training(self, data): self.categories={c:len(data[c]) for c in data} self.words={c:{} for c in self.categories} for c in data: for text in data[c]: tokens=self.tokenize(text) for w in tokens: if w not in self.words[c]: self.words[c][w]=int() self.words[c][w]+=1 self.smoothing=.1/(sum([sum(self.words[c].values()) for c in self.categories]))#初見の単語の確率を小さく設定 #学習済み分類器をつかって与えられた文書の分類をする def classification(self, test, uselog=True): p_categories=probability(self.categories) p_words={c:probability(self.words[c]) for c in self.categories} test=self.tokenize(test) results={} #以下がベイズの定理を使うところ。ここではlogを使って実装している。 if uselog: for c in self.categories: results[c]=math.log(p_categories[c]) for t in test: if t in self.words[c].keys(): results[c]+=math.log(p_words[c][t]) else: results[c]+=math.log(self.smoothing) #logを使わないと以下のようになる。 else: for c in self.categories: results[c]=p_categories[c] for t in test: if t in self.words[c].keys(): results[c]*=p_words[c][t] else: results[c]*=self.smoothing return results #与えられた文書を単語に分解する def tokenize(self,text): tokens=[] t=Tokenizer() pre_tokens=t.tokenize(text) for token in pre_tokens: tokens.append(token.surface) return tokens #出現頻度を割合に変換する def probability(dict): return {i:float(dict[i])/sum(dict.values()) for i in dict} nb=NaiveBayes() nb.pre_training('train_data') nb.training(nb.texts) #テストデータを用意する file='test.txt' f=open(file,'r') text=f.read() f.close() #学習済み分類器で分類する print(nb.classification(text))


「このモデルを利用して、スポーツニュースの文章を入力として、野球の記事なのか、サッカーの記事なのかを予測しましょう」


「このプログラムと同じ階層に、train_dataディレクトリを作り、その下のbaseballディレクトリには野球の記事のテキストデータを、soccerディレクトリにはサッカーの記事のテキストデータを入れてみました。はたしてどちらに分類されるでしょうか…」


「野球の方が出てきた値が大きいですね。ということはインプットした文章が野球である可能性が高いことになりますね」


「このプログラムを簡単に説明すると、インプットした文章を形態素解析を行い、野球の記事に出てきやすい単語、サッカーの記事に出てきやすい単語をそれぞれ集計します。それが新しくインプットした文書にどれくらい出てくるかをみているというわけです」


「ちなみに、このプログラムのどこでベイズの定理が使われているんですか?ベイズの定理はさきほどやったようにP(Y|X)=P(X|Y)P(Y)P(X)という公式だったと思いますが、それらしい計算をしているところが見当たりません」


「実はその処理はclassificationメソッドの中で行っています。つまり今回のプログラムでは、P(野球|文書)とP(サッカー|文書)を比較してどちらが大きいかを見ているわけですが、分母はどちらもP(文書)となっているので、省略しています」


「お気付きかもしれませんが、インプットした文章と同じものを丸々学習させているわけではないので、完全なるP(文書|野球)は求めることはできません。この確率の代わりにP(単語[0]|野球) * P(単語[1]|野球) * P(単語[2]|野球) * … * P(単語[k]|野球)で単純化して計算しています。なのでこのモデルのことを、「ナイーブベイズ分類器」と呼びます」


「でもこれたくさん文書を学習させると、値がどんどん小さくなっていきますね」


「その通りです。なのでここではlogを使って値が小さくなるのを防いでいます。大小を比べるだけだったらどっちでも同じですね。もし気になる方はuselog=Falseとしてみてください」


「なるほど、今まで機械学習ってブラックボックスだと思っていましたが、基本になっているのはベイズの定理のようなシンプルな公式の応用なんだと思うと、ちょっと親しみがわきますね」

次回は確率分布のパラメーターの推定を扱います。そこで必要な数学として微分について説明します。次回もどうぞお楽しみに!

CodeIQで機械学習クイズに挑戦しよう!

機械学習の理解度をはかるクイズに挑戦してみませんか?
ITエンジニアのスキルの腕試しができる「CodeIQ」では初心者向けの基礎知識をチェックできるクイズを出題中!
ぜひチャレンジしてみてくださいね♪

  • 117
  • このエントリーをはてなブックマークに追加

■関連記事

脱シンプルBot!Chatbotプログラムを最大限活用するためには?_... ダメBotはどうしたら賢くなれるのか? ※本企画はLINE株式会社の提供でお送りします。 こんにちは、池澤あやかです。 エンジニア界隈では、昨年ごろからChatbotが流行ってますよね。私もこのブームに乗じていくつかBotを作ってみたのですが、我ながら自作したBotには少し使いづらさを感じてい...
Bot開発のエキスパートに聞いた!プログラミング初心者こそChatbotを開発すべき理由とは?_... 2017年、Chatbotイヤー到来! ※本企画はLINE株式会社の提供でお送りします。 こんにちは、池澤あやかです。 テクノロジーの流行りには積極的に乗っていくスタイルを貫いています。 というわけで、今回はChatbot(チャットボット)がテーマです。 2016年から今年にかけて、Face...
池澤あやかとプログラミングで学ぼう!機械学習のための数学講座【行列編】... 機械学習のための数学ゼミ第三回は行列編! 第一回の「確率分布編」、第二回の「ベイズの定理編」に続き、第三回は行列編です。 まずは本連載の登場人物をご紹介します! <登場人物> 池澤あやか タレントときどきエンジニア。数学は苦手だけど、機械学習入門したい。 増井雄一郎 株式会社トレタのえ...
池澤あやかとプログラミングで学ぼう!機械学習のための数学講座【確率分布編】... 機械学習のための数学ゼミ開講! 今なにかと話題の機械学習。これを期に機械学習をはじめてみようかなと思っている方も多いのではないでしょうか。 しかし、実際に機械学習をはじめてみると、数字や数式、グラフのオンパレードに目眩を起こしそうになります。数学が苦手な方にとってはなかなかハードルが高いのが現状...
ドキッ!女性だらけの「第3級アマチュア無線技士試験勉強会」に潜入してみた!... 女性限定!第3級アマチュア無線技士試験勉強会 こんにちは、池澤あやかです。 いろいろな技術系勉強会に潜入している私ですが、今回潜入したのは、エレクトロニクスとアマチュア無線の専門出版社、CQ出版が主催する「女性限定!第3級アマチュア無線技士試験勉強会」です!! アマチュア無線というと、高校...
ブラウザでVR?なにそれおいしいの?池澤あやかがWebVRの勉強会に潜入してみました!... WebにVRを求めるのは間違っているだろうか? 今回潜入してきた勉強会は、渋谷のイベントスペースdots.で行われた「html5j Webプラットフォーム部勉強会 第13回勉強会~WebにVRを求めるのは間違っているだろうか?~」。 ▲受付嬢は、勉強会やハッカソンでよく見るあの人だ…! ...

今週のPickUPレポート

新着記事

週間ランキング

CodeIQとは

CodeIQ(コードアイキュー)とは、自分の実力を知りたいITエンジニア向けの、実務スキル評価サービスです。

CodeIQご利用にあたって
関連サイト
codeiq

リクルートグループサイトへ