🦕

いろんなClassifierの決定境界を可視化してみた

2022/03/05に公開

sklearn公式でもここにあったが、自分メモ用にいろんなClassifierの決定境界を可視化してみた。

試したのは

  • sklearn SVC(linear)
  • sklearn SVC(rbf)
  • sklearn MLP
  • sklearn kNN
  • sklearn Gaussian Naive Bayes
  • sklearn Decision Tree
  • sklearn Random Forest
  • sklearn Adaboost
  • sklearn Gradient Boosting
  • sklearn Hist Gradient Boosting
  • XGBoost
  • LightGBM
  • Catboost
  • Tabnet

前準備

!pip install -q catboost pytorch-tabnet

import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

使ったデータ

今回使うシミュレーションデータは3クラス分類の2次元データ。

xs, ys = make_blobs(n_samples=1_000, centers=3, cluster_std=1, random_state=0)

可視化すると、こんなデータ。

plt.scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)
plt.show()

決定境界を見るためのコード

学習済みのclassifierを渡せば良いように書いた。

2枚表示されるが、左図は学習データにズームしたVer、右図はズームアウトしたVer。

def simulate(clf, x_min=-6, x_max=6, y_min=-4, y_max=8):
    fig, ax = plt.subplots(1, 2, figsize=(18, 6))

    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01))
    z = clf.predict(np.array([xx.ravel(), yy.ravel()]).T)
    ax[0].contourf(xx, yy, z.reshape(xx.shape), alpha=0.2, cmap=plt.cm.coolwarm)
    ax[0].scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)

    xx, yy = np.meshgrid(np.arange(x_min*2, x_max*2, 0.01), np.arange(y_min*2, y_max*2, 0.01))
    z = clf.predict(np.array([xx.ravel(), yy.ravel()]).T)
    ax[1].contourf(xx, yy, z.reshape(xx.shape), alpha=0.2, cmap=plt.cm.coolwarm)
    ax[1].scatter(xs[:, 0], xs[:, 1], c=ys, s=10, cmap=plt.cm.coolwarm)
    plt.show()

可視化結果

ほとんどハイパーパラメータのチューニングはしていない。

SVC(kernel='linear')

from sklearn.svm import SVC

clf = SVC(kernel='linear')
clf.fit(xs, ys)

simulate(clf)

直線の境界なので見た目がシンプル。

SVC(kernel='rbf')

clf = SVC(kernel='rbf')
clf.fit(xs, ys)

simulate(clf)

赤い境界が外全部を囲むので、とびっきりの外挿が来たらやばそう。

MLPClassifier

from sklearn.neural_network import MLPClassifier

clf = MLPClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

ズームしているとちょっと折線になってる。が、全体的にあシンプルな境界。層が小さいから?

KNeighborsClassifier

from sklearn.neighbors import KNeighborsClassifier

clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(xs, ys)

simulate(clf)

ズームアウトするとシンプルだが、ズームインすると複雑な境界面がある。

GaussianNB

from sklearn.naive_bayes import GaussianNB

clf = GaussianNB()
clf.fit(xs, ys)

simulate(clf)

直線っぽいが、ちょっと学習データの分布に引っ張られてちょっと曲線の境界?

DecisionTreeClassifier

from sklearn.tree import DecisionTreeClassifier

clf = DecisionTreeClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

ちょっと外れたデータの判別に境界が引っ張られる分、外挿にはロバストとは見えない。

RandomForestClassifier

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

DecisionTreeよりも決定境界に柔軟さがあるように見える。

AdaBoostClassifier

from sklearn.ensemble import AdaBoostClassifier

clf = AdaBoostClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

赤の決定境界が一部青側にあってちょっと気持ち悪い。

GradientBoostingClassifier

from sklearn.ensemble import GradientBoostingClassifier

clf = GradientBoostingClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

RandomForestよりも細かい境界が多く見える。ちょっと

HistGradientBoostingClassifier

from sklearn.ensemble import HistGradientBoostingClassifier

clf = HistGradientBoostingClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

ズームアウトした境界はRandomForestよりもシンプルに見えて違和感も少ない。
これがlightgbmにインスパイアされたものらしいので、lightgbmとほとんど同じに見える。

XGBClassifier

import xgboost as xgb

clf = xgb.XGBClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

LGBMClassifier

import lightgbm as lgb

clf = lgb.LGBMClassifier(random_state=0)
clf.fit(xs, ys)

simulate(clf)

CatBoostClassifier

from catboost import CatBoostClassifier

clf = CatBoostClassifier(random_state=0, metric_period=100)
clf.fit(xs, ys)

simulate(clf)

けっこう決定境界が外れ値に引っ張られた結果になっている。

TabNetClassifier

from pytorch_tabnet.tab_model import TabNetClassifier

clf = TabNetClassifier(seed=0)
clf.fit(xs, ys)

simulate(clf)

全体的にはきれいに境界があるように見えるが、上の部分に赤が突然出てきたり、極端な外挿で変な挙動をしそう。

Discussion