見出し画像

scikit-learn機械学習⑩ナイーブ・ベイズ実践編

前回は、ナイーブ・ベイズの理論的な側面を解説しました。今回は、この理論を実際のコードに落とし込んで、具体的なデータ分析を行います。

データセットとしては、scikit-learn.datasets からアイリス(iris、アヤメ)を使用します。このデータセットに含まれる花の特徴から花の種類を予測するタスクは、統計的手法を用いるナイーブ・ベイズを試すのにピッタリです。

まずは、探索的なデータ分析を行い、学習とテストのためにデータに前処理を施します。そして、訓練を行った後に評価をするという流れをコードを書きながら解説します。

さらに、ナイーブ・ベイズがどのようにしてベイズ定理を利用するための各確率を計算するのかをアイリスのデータセットを使って具体的に解説します。


Python環境の設定

Pythonの環境設定については以前と同様で、仮想環境を作ってscikit-learnなど必要なライブラリをインストールします。

mkdir naive_bayes
cd naive_bayes

# 仮想環境を作る
python3 -m venv venv
source venv/bin/activate

# pip をアップグレードしておく
pip install --upgrade pip

# 必要なライブラリをインストール
pip install scikit-learn jupyter matplotlib pandas

Jupyterノートブックを立ち上げてPython3のノートブックを作成してください。Jupyterノートブックに関しては、こちらを参照してください。

あるいは、VSCode(Visual Studio Code)を使ってJupyterノートブックを作成しても構いません。私は、どちらかというとVSCodeをよく使います。これについてもこちらで簡単に解説しています。

データの読み込み

アイリスのデータセットは、scikit-learn から次のように読み込みます。

from sklearn.datasets import load_iris

# データセットの読み込み
data = load_iris(as_frame=True)

as_frame=True と指定しているのは、データを pandas のデータフレームとして読み込むためです。

なお、データセットの説明は、次のように確認できます。

print(data.DESCR)

説明は長いので一部のみをここに掲載します。

.. _iris_dataset:

Iris plants dataset
--------------------

**Data Set Characteristics:**

:Number of Instances: 150 (50 in each of three classes)
:Number of Attributes: 4 numeric, predictive attributes and the class
:Attribute Information:
    - sepal length in cm
    - sepal width in cm
    - petal length in cm
    - petal width in cm
    - class:
            - Iris-Setosa
            - Iris-Versicolour
            - Iris-Virginica

:Summary Statistics:

============== ==== ==== ======= ===== ====================
                Min  Max   Mean    SD   Class Correlation
============== ==== ==== ======= ===== ====================
sepal length:   4.3  7.9   5.84   0.83    0.7826
sepal width:    2.0  4.4   3.05   0.43   -0.4194
petal length:   1.0  6.9   3.76   1.76    0.9490  (high!)
petal width:    0.1  2.5   1.20   0.76    0.9565  (high!)
============== ==== ==== ======= ===== ====================

データには、それぞれの花について以下の4つの特徴が測定されています。

  • sepal length:がく片の長さ(cm)

  • sepal width:がく片の幅(cm)

  • petal length:花弁の長さ(cm)

  • petal width:花弁の幅(cm)

そして、ターゲットのクラスは次の3種類のアヤメの花です。

  • Iris-Setosa:セトサ

  • Iris-Versicolour:バージカラー

  • Iris-Virginica:バージニカ

pandas を使ってデータを少し見てみます。

data.frame.head()

ターゲットの0は何でしょうか。ターゲットの名前を見てみます。

data.target_names

ターゲット値の0は setosa (セトサ)であるのがわかります。

データの探索的分析

前回解説したようにナイーブ・ベイズでは、特徴間の条件付き独立性を仮定しています。

特徴間の条件付き独立性とは、あるクラスが与えられた条件下で、各特徴は他の特徴から独立していると仮定することです。

これをアイリスのデータセットに当てはめると、例えば、ターゲットがセトサであるとしたときに、各特徴である「がく片の長さ」、「がく片の幅」、「花弁の長さ」、「花弁の幅」には相関がないと仮定しています。

では、実際にアイリスのデータセットの特徴間の相関係数を計算してグラフ化してみましょう。

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris

# データセットの読み込み
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)

# 相関係数行列の計算
correlation_matrix = iris_df.corr()

# 相関係数行列のヒートマップを作成
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, 
            annot=True, 
            cmap='coolwarm', 
            fmt=".2f", 
            linewidths=.5)
plt.title('Feature Correlation Matrix')
plt.show()

これを実行すると、次のような相関関係の図が表示されます。

これを見ると、実際には、いくつかの特徴間で強い正の相関が確認できます。

  • がく片の長さ(sepal length)花弁の長さ(petal length)との間には強い正の相関(0.87)がある

  • がく片の長さ(sepal length)花弁の幅(petal width)との間には強い正の相関(0.82)がある

  • 花弁の長さ(petal length)花弁の幅(petal width)は非常に強い正の相関(0.96)がある

また、負の相関も見られます。

  • がく片の幅(sepal width)と 花弁の幅(petal width) との間にはわずかな負の相関(-0.36)がある

要するにアイリスのデータセットでは、特徴間は独立ではありません。

しかし、前回に解説したように、ナイーブ・ベイズはこのような相関がある場合でも、しばしば良好なパフォーマンスを発揮することが知られています。実際にどうなるか実験してみましょう。

データの分割と標準化

まず、訓練用とテスト用にデータを分割します。

from sklearn.model_selection import train_test_split

# データセットを訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.2, random_state=0)

test_size = 0.2 と指定して、80%を訓練用、20%をテスト用にしました。random_state = 0 として再現性の確保のために乱数シードを固定しました。

特徴量の値の範囲などを訓練データから確認します。

X_train.describe()

こうしてみると、データの最大値、最小値、平均、標準偏差などに何十倍もの差があるわけでもなく、また同じ単位(cm)なので、このまま訓練しても問題はなさそうですが、一応、次に、データの標準化を行います。

from sklearn.preprocessing import StandardScaler

# まず、訓練データから平均と標準偏差を計算する
scaler = StandardScaler()
scaler.fit(X_train)

# スケーラ(scaler)を使って、訓練データとテストデータを標準化する
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

ちなみに、ナイーブ・ベイズでは特徴量が独立しているため、理論上はデータの標準化は必要ありません。しかし、コンピュータの数値計算の限界を考慮し(特に分散が小さい特徴量で値のずれが確率に大きな影響を与えるため)、データセットによっては標準化を行うことでモデルの性能が良くなる可能性もあります。実際に標準化の有無で結果を比較するのも一考です。

ガウス型ナイーブ・ベイズ

では、標準化された訓練データを使ってナイーブ・ベイズを実行しましょう。今回は、GaussianNB(ガウス分布を使ったナイーブ・ベイズ)を使います。

from sklearn.naive_bayes import GaussianNB

# ガウスナイーブ・ベイズ分類器のインスタンスを作成
model = GaussianNB()

# モデルの訓練
model.fit(X_train, y_train)

GaussianNB() によるモデルの訓練について説明すると、fit メソッドは訓練データセットを使って、各クラスに対する特徴量の平均と分散を計算します。ガウス分布を仮定しているので、存在しない特徴量に対しても平均と分散だけで確率を計算することが可能です。後でもう少し詳しく解説します。

次に、テストデータを使ってモデルの予測精度を評価します。

from sklearn.metrics import accuracy_score

# テストデータに対する予測
y_pred = model.predict(X_test)

# 予測精度の評価
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy:.2f}')

97%の正解度なので、かなり良い正解率です。よって、特徴量の間に相関があるデータセットでもよく機能することが確認できました。

クラスごとの評価も確認してみましょう。

from sklearn.metrics import classification_report

print(classification_report(y_test, y_pred))

どのクラス(0、1、2)に対しても、精度(precision)、再現率(recall)、F1スコア(f1-score)の全てが良いのが確認できます。しいて言えば、クラス2(バージニカ)に対する再現率(0.83)がちょっと低めではあります。このクラスの数が6で他のクラスの半分ぐらいなのが関係あるのかもしれません。

なお、これらの評価値についての詳細はこちらでも解説しています。

ガウス分布による確率

さて、ガウス分布を使ったナイーブ・ベイズが訓練データに fit しているときの処理をここで解説します。

ベイズ定理

まず、ベイズ定理をアイリスのデータセットに当てはめて簡単に復習します。

$$
P(Y \mid X) = \frac{P(X \mid Y)  P(Y)}{P(X)}
$$

ここで、$${P(Y \mid X)}$$、特徴$${X}$$が与えられたときのクラス$${Y}$$の条件確率です。ベイズ統計の世界では、よく事後確率(posterior probability)と呼ばれます。

なぜなら、特徴$${X}$$が観測された後に、クラス$${Y}$$の確率を予測しているからです。「事後」には、情報が得られた「後」の確率を意味がニュアンスとしてあります。情報を得て確率を更新するということです。

ただし、平たくいうと条件確率であり、「事後」という言葉に時間的な流れの意味はありません。

なお、アイリスのデータセットにおける特徴$${X}$$は「がく片の長さ」、「がく片の幅」、「花弁の長さ」、「花弁の幅」の4つを含みます。また、クラス$${Y}$$は、「セトサ」、「バージカラー」、「バージニカ」で、0、1、2のどれかです。

$${P(X \mid Y)}$$ は尤度(likelihood)と呼ばれ、クラス$${Y}$$が与えられたときの特徴$${X}$$の確率です。

$${P(Y)}$$は事前確率(prior probability)と呼ばれ、情報が得られる前のクラス$${Y}$$の確率です。

$${P(X)}$$は証拠(evidence)と呼ばれ、ある特徴$${X}$$が生じる確率です。言い方を変えると、すべての可能なクラスに渡る$${X}$$の尤度の合計です。

ベイズの定理を使うには、アイリスの訓練データセットからあらかじめ尤度や事前確率を計算できるように準備する必要があります。以下のような計算が、GaussianNB の fit で行われています。

事前確率の計算

アイリスのデータセットでは、各クラス(セトサ、バージカラー、バージニカ)の事前確率$${P(Y)}$$は同じで1/3です。これはデータセットが完全に均等に分割されているためです。

尤度の計算

特定のクラス$${Y}$$が与えられたときの特徴$${X}$$の尤度$${P(X \mid Y)}$$を計算するにはどうすれば良いでしょうか。特徴$${X}$$には4つの異なる特徴量が含まれています。

ここで、特徴量が互いに独立である仮定が役に立ちます。各特徴量の確率を別々に計算して、全てを掛け合わせれば良く計算が単純になります。また、ガウス型ナイーブ・ベイズでは、各特徴量はガウス分布に従うと仮定しているので、必要なのは各クラスごとに、全ての特徴量に対して平均と分散を計算しておけば十分です。

例えば、セトサのクラスでの「がく片の長さ」の平均と分散を用いて、新しい花の「がく片の長さ」の尤度をガウス分布を使用して計算します。これを花弁の長さ、幅など他のすべての特徴に対しても同様に行います。

証拠の計算

全てのクラスにわたる特徴の尤度$${P(X \mid Y)}$$を合計することで、証拠$${P(X)}$$の確率を計算ができます。これにより、観測された特徴がどれだけ一般的かがわかります。

事後確率の計算

ベイズ定理に基づいて、事後確率$${P(Y \mid X)}$$を計算することができます。

$$
P(Y \mid X) = \frac{P(X \mid Y) \times P(Y)}{P(X)}
$$

例えば、新しいサンプルの「がく片の長さ」、「がく片の幅」、「花弁の長さ」、「花弁の幅」の値から、セトサ、バージカラー、バージニカのそれぞれについて事後確率を計算します。

すべてのクラスに対して事後確率を計算した後、最も事後確率が高いクラスがそのサンプルのクラスとして予測されます。この計算により、特定の花の特徴が与えられたときに、それがどのアイリスの種類であるかが最も確からしいかが判定されます。


以上より、ナイーブ・ベイズは非常に明解な理論を持ち、データを使って実際に有効であることが確認できました。

次回予告

次回は、決定木(Decision Tree)を紹介します。

お楽しみに!

いいなと思ったら応援しよう!