ロジスティック回帰では、データを2つのクラスに分類する方法を学びました。しかし、実社会ではサンプルが3つ以上のクラスに分けられる問題も多くあります。
ここからのレクチャーでは、こうした問題に対応出来る、多クラス分類の方法を学びます。
1.) Iris(アヤメ)データの紹介
2.) ロジスティック回帰を使った多クラス分類の紹介
3.) データの準備
4.) データの可視化
5.) scikit-learnを使った多クラス分類
6.) K近傍法(K Nearest Neighbors)の紹介
7.) scikit-learnを使ったK近傍法
8.) まとめ
機械学習のサンプルデータとして非常によく使われるデータセットがあります。 それが、Iris(アヤメ)のデータ です。
このデータセットは、イギリスの統計学者ロナルド・フィッシャーによって、1936年に紹介されました。
3種類のアヤメについて、それぞれ50サンプルのデータがあります。それぞれ、Iris setosa、Iris virginica、Iris versicolorという名前がついています。全部で150のデータになっています。4つの特徴量が計測されていて、これが説明変数になります。4つのデータは、花びら(petals)と萼片(sepals)の長さと幅です。
# Iris Setosa
from IPython.display import Image
url = 'http://upload.wikimedia.org/wikipedia/commons/5/56/Kosaciec_szczecinkowaty_Iris_setosa.jpg'
Image(url,width=300, height=300)
# Iris Versicolor
from IPython.display import Image
url = 'http://upload.wikimedia.org/wikipedia/commons/4/41/Iris_versicolor_3.jpg'
Image(url,width=300, height=300)
# Iris Virginica
from IPython.display import Image
url = 'http://upload.wikimedia.org/wikipedia/commons/9/9f/Iris_virginica.jpg'
Image(url,width=300, height=300)
データの概要をまとめておきましょう。
3つのクラスがあります。
Iris-setosa (n=50)
Iris-versicolor (n=50)
Iris-virginica (n=50)
説明変数は4つです。
萼片(sepal)の長さ(cm)
萼片(sepal)の幅(cm)
花びら(petal)の長さ(cm)
花びら(petal)の幅(cm)
最も基本的な多クラス分類の考え方は、「1対その他(one vs all, one vs rest)」というものです。 複数のクラスを、「注目するクラス」と「その他のすべて」に分けて、この2クラスについて、ロジスティック回帰の手法を使います。
どのクラスに分類されるかは、回帰の結果もっとも大きな値が割り振られたクラスなります。
後半では、K近傍法という別の方法を紹介します。
# 英語になりますが、Andrew Ng先生の動画は、イメージを掴むのによいかもしれません。
from IPython.display import YouTubeVideo
YouTubeVideo("Zj403m-fjqg")
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
%matplotlib inline
サンプルデータを読み込みます。scikit-learnに付属しています。
from sklearn import linear_model
from sklearn.datasets import load_iris
# データの読み込み
iris = load_iris()
# 説明変数をXに
X = iris.data
#目的変数をYに
Y = iris.target
# 説明文です。
print(iris.DESCR)
X
Y
pandas.DataFrameにしておきましょう。
iris_data = DataFrame(X,columns=['Sepal Length','Sepal Width','Petal Length','Petal Width'])
iris_target = DataFrame(Y,columns=['Species'])
クラスが0,1,2の数字なので、文字列の名前を付けておきましょう。
def flower(num):
''' 数字を受け取って、対応する名前を返します。'''
if num == 0:
return 'Setosa'
elif num == 1:
return 'Veriscolour'
else:
return 'Virginica'
iris_target['Species'] = iris_target['Species'].apply(flower)
iris_target.head()
# まとめておきましょう。
iris = pd.concat([iris_data,iris_target],axis=1)
iris.head()
pairplotを使えば、簡単に全体像を把握できます。
sns.pairplot(iris,hue='Species',size=2)
全体像がよくわかります。
特徴量でアヤメの種類を予測できそうです。特に、Setosaは最も特徴的な花のようです。
次に、花びらの長さに注目して、ヒストグラムを描いてみましょう。
plt.figure(figsize=(12,4))
sns.countplot('Petal Length',data=iris,hue='Species')
その他の特徴量についても、可視化してみてください。
1対その他の方法論で、ロジスティック回帰を使った多クラス分類の挑戦してみましょう。
すでに説明変数Xと、目的変数Yが用意されているので、これを使って解析を進めて行きます。
データを学習用とテストように分けておきましょう。全体の40%がテストデータになるようにします。
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import train_test_split
logreg = LogisticRegression()
# データを分割します。テストが全体の40%になるようにします。
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.4,random_state=3)
# データを使って学習します。
logreg.fit(X_train, Y_train)
テストデータを使って、モデルの精度を確認してみましょう。
# 精度を計算するのに便利なツールです。
from sklearn import metrics
# テストデータを予測します。
Y_pred = logreg.predict(X_test)
# 精度を計算してみましょう。
print(metrics.accuracy_score(Y_test,Y_pred))
93%と高い精度が得られました。random_stateを指定すれば、再現性がある結果を得ることができます。
次に、K近傍法に進んで行きましょう。
K近傍法は英語で、k-nearest neighborなので、kNNと略されることもありますが、極めてシンプルな方法論です。
学習のプロセスは、単純に学習データを保持するだけです。新しいサンプルが、どちらのクラスに属するかを予測するときにだけ、すこし計算をします。
与えられたサンプルのk個の隣接する学習データのクラスを使って、このサンプルのクラスを予測します。 イメージをうまく説明した図がこちら。
Image('http://bdewilde.github.io/assets/images/2012-10-26-knn-concept.png',width=400, height=300)
★が新しいサンプルです。これを中心に、既存のサンプルのクラスを見ていきます。K=3ではAが1つ、Bが2つなので、分類されるクラスは、Bです。K=6とすると、A4つ、B2つなので、Aと判別されます。
Kの選び方によっては、同数になってしまうことがあるので注意が必要です。(アルゴリズムの中で、これを解決する方法論が実装されていることが多いです。)
Irisデータを使って、実際のPythonコードを見ていきましょう。
# K近傍法
from sklearn.neighbors import KNeighborsClassifier
# k=6からはじめてみます。
# インスタンスを作ります。
knn = KNeighborsClassifier(n_neighbors = 6)
# 学習します。
knn.fit(X_train,Y_train)
# テストデータを予測します。
Y_pred = knn.predict(X_test)
# 精度を調べてみましょう。
print(metrics.accuracy_score(Y_test,Y_pred))
95%の精度が得られました。k=1にするとどうなるでしょうか?もっとも近いサンプルのクラスを予測値とする方法です。
# 今度は、1です。
knn = KNeighborsClassifier(n_neighbors = 1)
knn.fit(X_train,Y_train)
Y_pred = knn.predict(X_test)
print(metrics.accuracy_score(Y_test,Y_pred))
kを変化させるとどうなるでしょうか?
# kを変化させてみましょう。
k_range = range(1, 90)
accuracy = []
# 先ほどの計算を繰り返して見ましょう。
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, Y_train)
Y_pred = knn.predict(X_test)
accuracy.append(metrics.accuracy_score(Y_test, Y_pred))
結果をプロットします。
plt.plot(k_range, accuracy)
plt.xlabel('K for kNN')
plt.ylabel('Testing Accuracy')
学習用のデータとテスト用のデータを分けるやり方を変えると、これらの結果がどうなるか、検討してみるのも面白いかもしれません。
ロジスティック回帰とk近傍法を使った多クラス分類について学びました。
英語になりますが、参考資料をいくつかあげておきます。
1.) Wikipedia on Multiclass Classification
2.) MIT Lecture Slides on MultiClass Classification