はじめに
線形な分類器は癒やし
やれ、RBFカーネルだ、決定木だ、ニューラルネットだ、深層学習だ、と流行り物に乗っかって、言うことを聞かない非線形な分類器をなんとかねじ伏せている私たちは、きっと心が荒んでいるのでしょう。
そんな私たちに、線形分類器は癒やしを提供してくれます。
といってもいろいろありますよね。そこで比較してみることにしました。
実験
sklearnの線形モデルは本当にたくさんあってどれを選べば良いのかわからないのですが(参考:API Reference — scikit-learn 0.20.1 documentation)、3つに絞りました。
- 線形判別分析
- ロジスティック回帰
- 線形SVM
「あっ、教科書に載ってる奴だ」というモデルたちですね。
二次元で適当なデータを分類させて、決定関数を見ます。
プログラムを以下に示します。以下のページを大いに参考にしました。
Classifier comparison — scikit-learn 0.20.1 documentation
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.linear_model import LogisticRegression from sklearn.svm import LinearSVC from sklearn.metrics import accuracy_score from sklearn.datasets import make_blobs, make_moons def main(): moons_X, moons_y = make_moons(noise=0.2, random_state=0) blobs_X, blobs_y = make_blobs(centers=2, random_state=0) blobs2_X, blobs2_y = make_blobs(centers=3, random_state=1) blobs2_y[blobs2_y == 2] = 1 lda = LinearDiscriminantAnalysis() logistic = LogisticRegression() svm = LinearSVC() fig, axes = plt.subplots(nrows=3, ncols=3) plt.subplots_adjust(hspace=0.5) cm = plt.cm.RdBu cm_bright = ListedColormap(['#FF0000', '#0000FF']) for i, (X, y) in enumerate([(moons_X, moons_y), (blobs_X, blobs_y), (blobs2_X, blobs2_y)]): x_min, x_max = X[:, 0].min()-0.5, X[:, 0].max()+0.5 y_min, y_max = X[:, 1].min()-0.5, X[:, 1].max()+0.5 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1)) for j, (cname, clf) in enumerate([("LDA", lda), ("LogisticRegression", logistic), ("LinearSVM", svm)]): clf.fit(X, y) if hasattr(clf, "decision_function"): Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) else: Z = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1] Z = Z.reshape(xx.shape) axes[i,j].contourf(xx, yy, Z, 20, cmap=cm, alpha=.8) axes[i,j].scatter(X[:,0], X[:,1], c=y, s=20, cmap=cm_bright, edgecolors="black") axes[i,j].set_title(cname) preds = clf.predict(X) axes[i,j].text(xx.max() - .3, yy.min() + .1, "{:.3f}".format(accuracy_score(y, preds)), size=10, horizontalalignment='right') plt.savefig("result.png") if __name__ == "__main__": main()
結果
行がデータ、列が分類機に対応。
色の濃淡が決定関数の値か出力値のラベルの確率に対応。右下の値は学習に使ったデータでテストして計算した正解率です*1。
基本的に変わり映えがしない。そこがいい。
と言っていては何の考察にもならないので、ざっくりと説明。
えーっと、まず正解率の大小に大した意味はありません。誤差です。
最上段の三日月状のデータはもともと線形分離できないようなデータです。どれも似通った決定関数になっています。
中段は正規分布2つが微妙に重なっているようなデータで、ロジスティック回帰だけ微妙に傾き方が大きい気がします。正解率も(大した意味はないとはいえ)微妙に下がっている。何を思ってこうしたのか。
最下段は正規分布3つを1つ+2つで2つのクラスに分けたデータです。どれも正解率100%になっていますが、LDAはデータ全体の傾向からそれっぽい決定関数を導いているのに対し、ロジスティック回帰とSVMはそういう配慮はないようです。線形判別分析がよくてロジスティック回帰やSVMが駄目という話ではないのですが、こういうデータに対しては単純な判別分析の方がそれっぽく動くということでしょうか。
まとめ
この中からどれか選ぶとしたら? という建設的な話を期待した方には申し訳ありませんが、やっぱり「どれを選んでもそんなに変わらない」という結論になる気がします。
強いて言えば、わかりやすい判別分析か、とりあえずSVM的な線形SVMの二択? ロジスティック回帰は非等分散、非正規分布のデータに対する有効性や、確率モデルとして取り扱えることにどこまで価値を見出すかによって使うか使わないかが決まる気がします。実際的には評価指標の比較をやっても良いと思いますが、正直そこまで劇的な差は出てこないと思う。
*1:交差検証とかはやっていません。この記事は癒やしが目的なので