アヤメの種類判別(その7)

実行例は「saka.mokumoku」の「Google Colabotry」環境に保存してある

1.iris データセットの説明

 データセットのロード
   load_iris 関数でロードする

 データセットの説明
    DESCR (description) の中身を見る
     Attribute の意味
       sepal length:ガクの長さ
       sepal width:ガクの幅
       petal length:花弁の長さ
       petal width :花弁の幅

from sklearn.datasets import load_iris
iris = load_iris()
#
print(iris.DESCR)

 データセットの内容
   データセットの形状・・・特徴量は 4 個で、150 個のデータ
               形状は shape で確認する

   花の種類・・・target_names に3種類の花が格納されている
          setosa、’versicolor、’virginica

   先頭5件・・・iris.data
             4 つの特徴量(ガクの長さ、幅、花弁の長さ、幅)
          iris.target
            3種類、0(=setosa), 1(=versicolor), 2(=virginica)

print(iris.data.shape)
#
print(iris.target_names)
#
for data, target in zip(iris.data[:5], iris.target[:5]):
  print(data, target)

2.データフレーム作成

 データフレームにするとデータを扱いやすくなる
   target の行が 0, 1, 2 だと分かりにくいので種類名に置き換える

   describeで平均値、最小、最大値を眺める

import pandas as pd
#
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['target'] = iris.target
df.loc[df['target'] == 0, 'target'] = "setosa"
df.loc[df['target'] == 1, 'target'] = "versicolor"
df.loc[df['target'] == 2, 'target'] = "virginica"
#
print(df.describe())

3.ペアプロットする

 各特徴量のペアごとに散布図を表示する
   特徴量のペアで見ても同じ品種が固まっているので、比較的分類しやすい

import seaborn as sns
#
sns.pairplot(df, hue="target")

4.分類アルゴリズム

 分類アルゴリズムの特徴を見るために
   作成したモデルの決定境界(decision boundary)を表示する

   モデルを validation 用、test 用に分けたり、正答率の評価は行わない

   X に訓練データをセットする
     特徴量はガクの長さ、花弁の長さの2つだけを使用する
   y に教師データとして品種をセットする

   描画用にコードを準備する

# import some data to play with
X = iris.data[:, [0, 2]] 
y = iris.target

import numpy as np
import matplotlib.pyplot as plt

# graph common settings
h = .02  # step size in the mesh
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))

def decision_boundary(clf, X, y, ax, title):
    clf.fit(X, y)
    
    # Plot the decision boundary. For that, we will assign a color to each
    # point in the mesh [x_min, x_max]x[y_min, y_max].    
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    
    # Put the result into a color plot
    Z = Z.reshape(xx.shape)
    ax.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)
    
    # Plot also the training points
    ax.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', cmap=plt.cm.Paired)
    
    # label
    ax.set_title(title)
    ax.set_xlabel('sepal length')
    ax.set_ylabel('petal length')

5.教師あり学習

 k-近傍法 (k-NN)
   モデルには訓練データセットを格納するだけ
     予測時は、予測したいデータポイントの近くの k 個の近傍点を確認し
     その中で一番多数派のクラスを予測結果として採用する

   KNeighborsClassifierを使用する
     n_neighbors で予測に使用する近傍点の数を設定する
       n_neighbors = 1 の場合は決定境界が鋭角になる部分もある
       数が多くなるに従いなだらかになっていき、
         10 になると境界が単純になりすぎて予測性能が落ちる

from sklearn.neighbors import KNeighborsClassifier

fig, axes = plt.subplots(1, 4, figsize=(12, 3))

for ax, n_neighbors in zip(axes, [1, 3, 6, 10]):
    title = "%s neighbor(s)"% (n_neighbors)
    clf = KNeighborsClassifier(n_neighbors=n_neighbors)
    decision_boundary(clf, X, y, ax, title)

 ロジスティック回帰
   回帰とあるが、分類アルゴリズム

   LogisticRegressionを使用する
     決定境界は直線になる
     C は正則化の度合いを調整するパラメータ
       正則化は学習時にペナルティを与えることで過学習を抑える
       C を大きくすると正則化が弱くなり過学習気味になる
       Cを小さくするとデータの特徴を大雑把にしか獲得できない

   ロジスティック回帰などの線形モデルは
     高次元(特徴量の数が多い)のデータに対して有効
       高速のため、他の手法では学習できない

from sklearn.linear_model import LogisticRegression

fig, axes = plt.subplots(1, 3, figsize=(10, 3))

for ax, C in zip(axes, [0.01, 1, 100]):
    title = "C=%s"% (C)
    clf = LogisticRegression(C=C)
    decision_boundary(clf, X, y, ax, title)

 線形サポートベクタマシン
   LinearSVCを使用する
     線形なので、決定境界も直線になる
     C はロジスティック回帰同様、正則化の度合いを調整するパラメータ

from sklearn.svm import LinearSVC

fig, axes = plt.subplots(1, 3, figsize=(10, 3))

for ax, C in zip(axes, [0.01, 1, 100]):
    title = "C=%s"% (C)
    clf = LinearSVC(C=C)
    decision_boundary(clf, X, y, ax, title)

 カーネル法を用いたサポートベクタマシン
   SVM とも呼ばれる
     線形カーネルベクタマシンと比べて、非線形な分離が可能

     SVCを使用する
     C は正則化のパラメータ
     gamma は訓練データの影響が及ぶ範囲
       小さいと遠くまで、大きいと近くになる
         大きすぎると過学習になり
         小さすぎると大雑把にしかデータの特徴を獲得できない

from sklearn.svm import SVC

fig, axes = plt.subplots(3, 3, figsize=(10, 10))

for ax_row, C in zip(axes, [0.01, 1, 100]):
    for ax, gamma in zip(ax_row, [0.1, 1, 10]):
        title = "C=%s, gamma=%s"% (C, gamma)
        clf = SVC(C=C, gamma=gamma)
        decision_boundary(clf, X, y, ax, title)

 決定木
   質問を通してデータを分類する手法
     あやめの場合には
       花弁の長さが何センチ以上 or 未満
       ガクの長さが何センチ以上 or 未満・・・と質問を繰り返す

     DecisionTreeRegressor を使用する
       max_depth がツリーの深さで、質問数になる
         多ければいいわけでもなく、
         訓練データに過剰適合するので過学習となる

from sklearn.tree import DecisionTreeRegressor

fig, axes = plt.subplots(1, 3, figsize=(10, 3))

for ax, max_depth in zip(axes, [1, 3, 8]):
    title = "max_depth=%s"% (max_depth)
    clf = DecisionTreeRegressor(max_depth=max_depth)
    decision_boundary(clf, X, y, ax, title)

 ランダムフォレスト、勾配ブースティング回帰木
   ランダムフォレストは異なる決定木をたくさん作り
     全ての決定木で予測した結果から
     もっとも確率が高くなるラベルを正解とする

   個々の木だと過剰適合しているかもしれないが、
     多くの結果を集約することで過学習を抑制する効果がある

   RandomForestClassifier を使う
     勾配ブースティング回帰木もたくさんの決定木を作るが、
       一つ前の決定木の予測値と正解のズレを修正するように
       次の木を作っていく

     GradientBoostingClassifier を使う
       ランダムフォレストよりモデル構築に時間がかかり
       パラメータ設定のチューニングが大変らしいが、
       その分予測性能がよくなる
         GBDT = Gradient Boosting Decision Tree

from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier

fig, axes = plt.subplots(1, 2, figsize=(7, 3))
clfs = [RandomForestClassifier(), GradientBoostingClassifier()]
titles = ["RandomForestClassifier", "GradientBoostingClassifier"]

for ax, clf, title in zip(axes, clfs, titles):
    decision_boundary(clf, X, y, ax, title)

 ニューラルネットワーク
   MLPClassifier を使う
     隠れ層 15 個で計算した結果を図示する
       同じパラメータでも決定境界が異なってくる
         異なる理由は、異なる初期状態から学習を開始するから

from sklearn.neural_network import MLPClassifier

fig, axes = plt.subplots(1, 4, figsize=(12, 3))

for ax, n in zip(axes, [15, 15, 15, 15]):
    title = ""
    clf = MLPClassifier(hidden_layer_sizes=[n, n])
    decision_boundary(clf, X, y, ax, title)

6.教師なし学習

 k-means
   教師データなしで分類する手法

   KMeans を使う
     n_clustersで何個に分類するかを指定する

from sklearn.cluster import KMeans

fig, axes = plt.subplots(1, 4, figsize=(12, 3))

for ax, n_clusters in zip(axes, [2, 3, 4, 5]):
    title = "n_clusters=%s"% (n_clusters)
    clf = KMeans(n_clusters=n_clusters)
    decision_boundary(clf, X, y, ax, title)