E検定対策(4) - 単純パーセプトロン:ロジスティック回帰を用いた分類
今回からは教師あり学習の基本とその実例を、とりわけ実際にE検定の出題範囲にある問題に関しての記事を書いていきたいと思います。まずは単純パーセプトロンを用いた分類のアルゴリズム・ロジスティック回帰、サポートベクターマシーン、K近傍法についての記事とプログラミング例を紹介します。
ロジスティック回帰とは
ロジスティック回帰とは名前に「回帰」と入っていますが、実際は分類に利用されるアルゴリズムです。ある事象が起こる確率を予測、分析したい時に用いられるもので、データが各クラスに所属する確率を計算することで分類を行います。
ロジスティック回帰は、モデルが単純パーセプトロンとほぼ等価(※厳密には定義によって異なるらしい)であることが知られています。単純パーセプトロンの目的関数に確率を出力するシグモイド関数を用いることで生物の神経細胞を模倣し、順伝播による学習を行うという事ですね。
ロジスティック回帰をScikit-Learnで実装
以下はロジスティック回帰による分類を分類問題を解く際のセオリーを参考に実装した例になります。インポート・事前準備・前処理・学習・結果出力・視覚化という順を追って説明していきます。
インポート
NumpyとMayplotlib、SKLearnの必要変数をインポートします。今回は訓練・テストデータの分離、標準化の前処理、ロジスティック回帰のライブラリを入れてます。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
事前準備
分類をしたいデータセットを作成します。今回はnp.random.seed、np.random.multivariate_normalを用いています。説明変数と目的変数をそれぞれ別に作成したのちにnp.vstack、np.appendを用いて結合します。
np.random.seed(seed = 0)
#multvariate_normalの引数 => 平均、共分散、生成する個数
#目的変数が0のリスト
X_0 = np.random.multivariate_normal([2,2],[[2,0],[0,2]],100)
y_0 = np.zeros(len(X_0))
#目的変数が1のリスト
X_1 = np.random.multivariate_normal([6,7],[[3,0],[0,3]],100)
y_1 = np.ones(len(X_1))
#説明変数・目的変数を結合(vstack = 縦方向に配列を結合)
X = np.vstack((X_0,X_1))
y = np.append(y_0,y_1)
作成したデータセットを視覚化するとこんな感じです。
plt.scatter(X[y==0,0], X[y==0,1], c="red",marker="o",label = "y = 0")
plt.scatter(X[y==1,0], X[y==1,1], c="blue",marker="o",label = "y = 1")
plt.legend(loc = "upper left")
前処理
データを訓練用・テスト用に分割し説明変数を標準化します。
#データを訓練用・テスト用に分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3)
#特徴データをsklearn.preprocessing、StandardScaler(標準化)に通す(前処理)
sc = StandardScaler()
sc.fit(X)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
標準化した後の訓練用・テスト用データを視覚化します。標準化後のデータがどうなっているか、訓練・テストデータの割り振りに偏りがないかをこの段階でチェックしてください。
#標準化した後の訓練用・テスト用データを視覚化
plt.scatter(X_train_std[y_train==0,0], X_train_std[y_train==0,1], c="red",marker="x",label = "train 0")
plt.scatter(X_train_std[y_train==1,0], X_train_std[y_train==1,1], c="blue",marker="x",label = "train 1")
plt.scatter(X_test_std[y_test==0,0], X_test_std[y_test==0,1], c="red",marker="o",label = "test 0")
plt.scatter(X_test_std[y_test==1,0], X_test_std[y_test==1,1], c="blue",marker="o",label = "test 1")
plt.legend(loc = "upper left")
学習
訓練データを用いて単純パーセプトロンの学習を開始します。今回はLogisticRegression().fitを実行するだけで学習が完了します。
#ロジスティック回帰のアルゴリズムを呼び出す→訓練データを用いて学習開始(モデルの生成)
lr = LogisticRegression()
lr.fit(X_train_std, y_train)
#テストデータをモデルを用いて分類→精度を算出
print(lr.predict(X_test_std))
print(lr.score(X_test_std,y_test))
LogisticRegression().predictでテストデータの説明変数を用いた目的変数の予測を、LogisticRegression().scoreで予測精度の測定をできます。これで既存の説明変数から未知の目的変数を求められる、立派なAIの完成です。
精度は96.67%と、人間が手書きで直線を引くの以上に正確な値が弾き出せました。
結果出力・視覚化
最後に分類結果を出力します。単純パーセプトロン・ロジスティック回帰は線形分離をするためのアルゴリズムなので、分割線の切片・重みを出力しそれをグラフ上にプロットすることで分類結果を視覚化できます。
#結果の視覚化
#分割線の切片・重みを出力し、それをグラフ上にプロットする
w_0 = lr.intercept_[0]
w_1 = lr.coef_[0,0]
w_2 = lr.coef_[0,1]
print(list(map(lambda x:(-w_1 * x - w_0)/ w_2, [-2,2])))
#境界線をプロットし、データを重ねる
plt.plot([-2,2], list(map(lambda x:(-w_1 * x - w_0)/ w_2, [-2,2])))
plt.scatter(X_train_std[y_train==0,0], X_train_std[y_train==0,1], c="red",marker="x",label = "train 0")
plt.scatter(X_train_std[y_train==1,0], X_train_std[y_train==1,1], c="blue",marker="x",label = "train 1")
plt.scatter(X_test_std[y_test==0,0], X_test_std[y_test==0,1], c="red",marker="o",label = "test 0")
plt.scatter(X_test_std[y_test==1,0], X_test_std[y_test==1,1], c="blue",marker="o",label = "test 1")
plt.legend(loc = "upper left")
plt.show()
ロジスティック回帰の問題
ロジスティック回帰の問題は、線形分離可能なデータでないと正確な分類ができないという事ですね。「左端の点が入るようもっと柔軟に曲線で分類ができたらいいのに」と思いませんか?次回はこれらの問題をクリアし非線形なデータの分類ができる、サポートベクターマシーン・K近傍法による分類問題について執筆したいと思います。