学生による学生のためのデータサイエンス勉強会

【さきどりPython#8】ナーブベイズクラス分類器

historoid
historoid

こんにちは。清野(@historoid1)です。

今回はベイズモデルの紹介です。

機械学習でナイーブベイズ(NB)分類器を積極的に学ぶ人は少ないように感じます。やはり決定木やニューラルネットワークが人気で、NBを実用的に使っているひとは見たことがありません。

しかしNBが現代を代表する機械学習モデルです。多くの企業がベイズ理論を運営に応用しているそうです。

今回はそんなベイズ理論を使った機械学習モデルを紹介します。

ベイズ理論とは

教科書からの引用

ベイズ理論(Bayes’ theeorem)は、何らかの新しい情報 P(B | A) と、何らかのイベントが発生する確率P(A)に関する事前信念(prior belief)が与えられた際に、あるイベントが発生する確率P(A | B)を理解するための重要な方法だ。

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

historoid
historoid

ちょっと何言ってるかわかりません

教科書にそって用語の確認から始めていきましょう。

なおベイズ理論のネーミングセンスは独特で、初学者には理解しにくいところがあります。

ひと通り勉強して「だからこんな名称なのね」と腑に落ちます。

最初だけ我慢してください。

周辺確率 marginal probability: \(P(x_1, x_2, x_3, \dots, x_j)\)

いわゆる確率のことです。\(x_1\)や\(x_2\)は特徴量です。

サイコロの目を\(t\)としたとき、6の目が出る確率は\(P(t=6)\)と表現されます。これと全く同じです。

それからなんで周辺なの?と思うかもしれませんが、それはまた次回に説明します。

事後確率 posterior: \((y|x_1, \dots, x_j)\)

まずこの例では、1つのデータ(標本)には\(j\)個の説明変数(特徴量)があります。

このとき、それぞれの説明変数を\(j\)個分すべて観測して、その上でその標本がクラス\(y\)に属する確率が、\(P(y|x_1, \dots, x_j)\)です。

高校数学では条件付き確率と習ったでしょう。

posteriorは「後ろの」という意味です。時系列的に「後ろ」、位置的に「後ろ」など広く使われる言葉です。

ベイズ理論の文脈では「特徴量を観測したあと」という意味です。

\(P(y|x_1, \dots, x_j)\)はその結果になる確率です。原因となる事象(特徴)があり、それに対する結果(posterior) と考えてください。

尤度 likelihood: \(P(x_1, \dots, x_j|y)\)

「ゆうど」と読みます。「確からしさ」とか「もっともらしさ」という意味ですが、いまいちわからないですよね。言葉がふわふわしすぎています。

式の形としては、事後確率の中身が入れ替わったものになっています。これも形式的には条件付き確率です。

そのため式を日本語訳すると「その標本がクラス\(y\)に属しており、特徴量が\(x_1, \dots, x_j\)である確率」と読むことができます。

例を考えましょう。単純に血糖値だけで糖尿病かどうかを判別するとしましょう。

クラスは糖尿病と健康の2つだけで、特徴量は血糖値の1つだけです。

ここで尤度\(P(血糖値=100|健康)\)は「健康な人の血糖値が100である確率」ですよね。

一方で、事後確率\(P(健康|血糖値=100)\)は「血糖値100の人が健康である確率」です。全然意味が違いますよね?

事後確率は、「血糖値が100」という原因(特徴)が条件であり、その結果として「健康」に属することを示しています。

尤度は、「健康」という結果がすでにわかっていて、その人が「血糖値100」という特徴を示す確率を表しています。

その特徴を示す確率、と考えれば「もっともらしさ」や「確からしさ」という言葉がなんとなくわかってきます。

historoid
historoid

この違い分かりますか?

原因から将来(事後確率)を見るか、結果から原因(尤度)を見るかという視点の違いがあります。

事前確率 prior: \(P(y)\)

クラスが\(y\)である確率です。

なぜ「事前」なのか。「特徴量を観測する前」という意味です。事後確率と同じ理屈ですね。

ここからがベイズ理論らしいのですが、この確率は「思い込み」でもいいのです。教科書には「クラス\(y\)であると信じる確率」と書いてあります。\(P(y)\)事前信念ともいわれます。

historoid
historoid

ちょっと何言ってるかわかりませんね(2回目)。

これがベイズ理論の真骨頂というか、強みというか、面白いところですね。クラス\(y\)に属する確率は、統計学的に正しくなくてもいいのです。

逆にいうと、この「思い込みでOK」ということによってベイズ理論の適応範囲が広くなったのです。そのため、ベイズ理論は主観的な確率理論と説明されることもあります。

例えば「自分が外出しようとすると雨が降ってしまう確率」というのも思い込みで定義できます。

統計学的に正しい確率を出すならば、「自分」を何人も用意して、実際に雨が降る日にちをカウントしなければなりません。もちろんそんなことできません

しかしベイズ理論では思い込みでOKなので「ほんとに2回に1回は雨なんだよ!!」と思えば、\(P(rain)=0.5\)と定義できるのです。

ナイーブベイズ naive Bayes

教科書で取り扱うナイーブベイズ(NB)クラス分類器では、観測値(特徴量)からどのクラスに属するか(事後確率\(P(y|x_1, \dots, x_j)\))を推測します。

事後確率が最大となるクラスの探索

ここで条件付き確率の式をおさらいします。

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

これを事後確率にあてはめます。

$$P(y|x_1, \dots, x_j) = \frac{P(x_1, \dots, x_j|y)P(y)}{P(x_1, \dots, x_j)}$$

このように式変形できます。

ここで周辺確率\(P(x_1, \dots, x_j)\)は、クラスが\(y\)だろうと\(z\)だろうと変わりませんので、実際には分子をクラスごとに比較すればいいわけです。

そして分子部分は以下のように変形できます。

$$P(y)P(x_1,\dots,x_j|y)=P(y)\prod_{k=1}^{j}P(x_k|y)$$

そして事後確率が最大となるクラスを\(\hat{y}\)とします。機械学習において、^記号は「予測の」という意味を示します。

ナイーブベイズの前提

NBクラス分類器には2つの注意点があります。

1つは尤度\(P(x_j|y)\)の統計学的な分布を仮定しなければならない点です。一般的には、正規分布多項分ベルヌーイ分布を仮定します。

どんな分布を選択するかは、特徴量の性質(連続値なのか、2値なのかなど)で決まります

ナイーブベイズの「ナイーブ」とは

ナイーブは、日本語では「敏感な」とか「神経質な」という弱々しいイメージで使われていることもありますが、なんとなく「ナーバス neurvous」と混同している気もします。実際は「純粋な」とか「純朴な」、「垢抜けない」、「田舎臭い」という意味です。

NBにおいては「特徴量がそれぞれ独立」で、かつ「その尤度も独立」という仮定をナイーブといっています。

統計学でよく考えなければならないのは、特徴量同士に相関関係があるかどうかです

例えば1円玉を数えて金額を出すときに、枚数をカウントしようが、何グラムか計ろうが同じことです。金額に対する特徴量を「枚数」と「グラム数」に設定するのは全く意味がありません

観測を行うときに、上のような簡単な例であれば誰しもが「どちらか1つで十分」と判断します。しかし実際には特徴量同士の相関の強さは事前にはわかりません(観測が終わったあとに統計処理をしてはじめてわかります)。

つまりNBクラス分類器では「特徴量同士は無関係だよ」と仮定しているのです。

多くの場合、すべての特徴量が無相関ということはありえません。しかしそれでもNBは十分精度の高いクラス分類器を作ることができるのです。驚きですね。

ガウシアンナイーブベイズクラス分類器

最も一般的なNBクラス分類器は、ガウシアンNBクラス分類器です。

ガウシアンNBクラス分類器では、特徴量の尤度が正規分布に従うと仮定しています。

式で書くと以下のようになります。

$$ \begin{align} P(x_j|y) &= \frac{1}{\sqrt{2\pi\sigma^2_y}}e^{-\frac{(x_j-\mu_y)^2}{2\sigma_y^2}}\\&= \frac{1}{\sqrt{2\pi\sigma^2_y}}\exp(-\frac{(x_j-\mu_y)^2}{2\sigma_y^2})\end{align}$$

なお\(\sigma_y^2\)と\(\mu_y\)は、クラス\(y\)である場合の特徴量\(x_j\)の分散と平均値です。

そのため実際に特徴量が正規分布に従っているかはさておき、連続値であればガウシアンNBクラス分類器はうまく機能します(あくまで正規分布という仮定ですからね)。

ナイーブベイズ naive Bayes

ではscikit-learnでNBクラス分類器を実装してみましょう。

連続値特徴量に対するクラス分類器の訓練

# ライブラリのインポート
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB

# データのロード
iris = datasets.load_iris()
features = iris.data
target = iris.target

# モデルの作成
classifier = GaussianNB()

# モデルの訓練
model = classifier.fit(features, target)

ここまでいくつかsklearnでの実装を見てきましたが、書き方は一緒ですね。

新しい観測値を作るところも同じです。

# 新しい観測値を作る。
new_observation = [[4, 4, 4, 0.4]]

# クラスを予測する。
model.predict(new_observation)
# array([1])

事前確率(事前信念)を指定する

NBの面白さのひとつである事前確率を指定することもできます。

# ガウシアンNBを個々のクラスの確率を指定して作成
clf = GaussianNB(priors=[0.25, 0.25, 0.5])

# ガウシアンNBを訓練
model2 = clf.fit(features, target)

# 予測
model2.predict(new_observation)
# array([1])

irisデータはクラスが3つなので、リストで3つの事前確率を指定しています。

priorsを指定しないと観測データから計算して取得されます。

予測された事後確率の取り扱いに注意

ここで、ガウシアンNBクラス分類器が返す事後確率(予測)を求めてみましょう。

model.predict_proba([[4,4,4,0.4]])
# array([[1.34715602e-38, 9.99949727e-01, 5.02727760e-05]])

配列にそれぞれのクラスに属する事後確率が示されています。

クラス1に99.9%の確率で属すると予測されています。

しかしこの値をそのまま信じてはいけません。

さきほども書いたとおり、NBクラス分類器ではそれぞれの特徴量が独立であると仮定しています。

したがって特徴量同士の相関の強さに基づいて、事後確率を較正(こうせい)する必要があります

較正は、校正とも書きます。calibrationの訳です。

historoid
historoid

較正については2周目の勉強会でやりましょう。

その他のモデルの実装

特徴量が離散値の場合と、2値クラスの場合の実装を紹介します。

連続値特徴量に対するクラス分類器の訓練

# ライブラリ
import numpy as np
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer

# テキストを生成
text_data = np.array(['I love Brazil. Brazil!', 'Brazil is best', 'Germany beats both'])

# BoW特徴量を作成
count = CountVectorizer()
bag_of_words = count.fit_transform(text_data)

# 特徴量行列を作成
features = bag_of_words.toarray()

# ターゲットベクトルを作成
target = np.array([0, 0, 1])

# 事前確率を設定して多項ナイーブベイズクラス分類器を作成
classifier = MultinomialNB(class_prior=[0.25, 0.5])

# 多項ナイーブベイズクラス分類器を訓練
model = classifier.fit(features, target)

これは多項ナイーブベイズというモデルを使っています。

このモデルは特徴量が離散値で、多項分布に従っていることを仮定しています。

2クラス特徴量に対するNBクラス分類器の訓練

import numpy as np
from sklearn.naive_bayes import BernoulliNB

features = np.random.randint(2, size=(100, 3))
target = np.random.randint(2, size=(100, 1)).ravel()

classifier = BernoulliNB(class_prior=[0.25, 0.5])
model = classifier.fit(features, target)

このモデルは2クラス特徴量であることを仮定します。つまり、すべての特徴量が0か1のどちらかしかとらない、ということです(10と100、3と7でも何でもいいですけど)。


今回はこれでおしまいです。ベイズ理論についてはまた別の回に詳しく説明したいと思います。ではまた。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です