内容的には、前回の記事の続き的な感じになります。
pyhaya.hatenablog.com
今回は、二値分類をパーセプトロンを使って実装します。パーセプトロンといえば、ニューラルネットワークやディープラーニングの基本という感じの学習器です。前回に引き続き、理論を説明した後にPythonでの実装を示します。
対象とする問題
いくつかの特徴量が与えられていて、それに対して正解ラベルが+1, -1で与えられているような状況を考えます。考える仮説空間はhalf-spacesクラス(日本語訳がわからない)です。
仮説空間という言葉が出てくると難しく感じますが、予測に使うのは下のような関数です。
は重みとバイアスです。基本的には線形関数で、最終的にsignで符号だけ取り出すことで予測値
を算出しています。
どのように解くか
前回の記事では、これを線形計画問題だと考えて解きました。今回は、線形計画に比べると直感的な方法でパラメータを求めていきます。
まず、パラメータを
で初期化します。なぜこのような値で初期化するかというと、こうすることで
となって、ひとまず最初のデータに関して学習させることができるためです。
次にやることははこれで最適か調べることです。学習データを(2)式に代入していって、不等式が成り立っているか確かめます。すべての学習データで不等式が成立していればこのパラメータが最適値とすることができます。しかしほとんどの場合はこううまくはいきません。
番目のデータで
となってしまった場合を考えましょう。どうすればよいでしょう。要するに、左辺を増やす方向にを更新すればよいです。どうやるかというと、
このとき、(4)式の左辺は
となります。ここで、正解ラベルは±1しかとらないことを使いました。無事左辺を増やせました。このようにして、すべての学習データについて(2)式が成り立つまで値の更新を続けます。
Pythonでの実装
値の更新は、現実問題としてすべての学習データを間違えることなく予測することは不可能なことが多いので、適当なところで打ち切ります。100回の値更新で打ち切るようにしたのが下のプログラムです。
import numpy as np from sklearn.model_selection import train_test_split from sklearn.datasets import make_classification def Perceptron(X, y): X = np.array(X) w = np.zeros(len(X[0])) w = y[0] * X[0] for count in range(100): success = True for i in range(len(X)): if np.sign(w.dot(X[i])) == np.sign(y[i]): continue else: w += y[i]*X[i] success = False break if success: break return w if __name__ == '__main__': #サンプル生成 X, y = make_classification( n_samples=500, n_classes=2, n_features=2, n_redundant=0, class_sep=1.5, ) y = list(map(lambda x: -1 if x == 0 else 1, y)) X = np.array(X) y = np.array(y) X_train, X_test, y_train, y_test = train_test_split(X, y) w = Perceptron(X_train, y_train) accuracy = np.sum(y_test*X_test.dot(w) > 0) print(accuracy / len(X_test))
これを実行すると、だいたい95%程度の精度が出ていることが確認できます。