Pythonプログラマーで、機械学習を始めようと思っていますか?Scikit-Learnを使いこなすことから始めるとよいでしょう。
Scikit-Learn を使って分類を行うことは、学習したことを適用し始めるための簡単で単純な方法であり、ユーザーフレンドリーで文書化された堅牢なライブラリで実装することによって機械学習の概念を具体化することができます。
Scikit-Learnとは?
Scikit-Learnは2007年にDavid Cournapeauによって開発されたPython用のライブラリです。
分類やその他の機械学習タスクのために簡単に実装し、調整することができる有用なアルゴリズムの数々が含まれています。
Scikit-LearnはSciPyを基盤としているので、Scikit-Learnを利用する前にこのライブラリの基本スタックがインストールされている必要があります。
用語の定義
Scikit-Learnの探索を進める前に、用語を定義する時間を取りましょう。
Scikit-Learn の機能を説明するときに使われる語彙を理解しておくことが重要です。
そもそも機械学習システムあるいはネットワークは、入力と出力を受け取ります。
機械学習のフレームワークへの入力は、しばしば「特徴量」と呼ばれます。
特徴量とは、科学的な実験における変数と本質的に同じもので、何らかの方法で定量化したり測定したりできる、観察対象の現象の特性である。
機械学習のフレームワークにこれらの特徴が入力されると、ネットワークは特徴間の関連パターンを識別しようとする。
これらのパターンは、フレームワーク/ネットワークの出力を生成するために使用される。
フレームワークの出力はしばしば「ラベル」と呼ばれる。
出力特徴にはネットワークによって与えられたラベルがあり、出力がどのカテゴリに分類されるかについての何らかの仮定があるからである。
出典:Siyavula Education
機械学習の文脈では、分類は教師あり学習の一種である。
教師あり学習とは、ネットワークに供給されるデータがすでにラベル付けされており、重要な特徴や属性があらかじめ明確なカテゴリに分けられていることを意味する。
つまり、ネットワークは入力のどの部分が重要かを知っており、また、ネットワークが自分自身をチェックできるターゲットやグランドトゥルースも存在する。
分類の例としては、多くの異なる植物をシダ植物や被子植物のような異なるカテゴリに分類することが挙げられる。
このタスクは、Scikit-Learnの分類器の一種である決定木によって達成されるかもしれない。
これに対して教師なし学習は、ネットワークに供給されるデータがラベル付けされておらず、ネットワークがどの特徴が最も重要であるかを自ら学習しようとするものです。
前述の通り、分類は教師あり学習の一種であるため、この記事では教師なし学習の方法は取り上げないことにする。
モデルの学習プロセスとは、ニューラルネットワークにデータを投入し、データのパターンを学習させるプロセスです。
学習プロセスでは、データを取り込み、データセットの特徴を引き出します。
教師あり分類タスクの学習プロセスでは、ネットワークに学習データの特徴とラベルの両方が渡されます。
しかし、テスト時には、ネットワークには特徴のみが渡される。
テスト工程では、ネットワークが学習したパターンがテストされる。
ネットワークには特徴が渡され、ネットワークはそのラベルを予測しなければならない。
ネットワークのデータはトレーニングセットとテストセットに分けられ、2つの異なる入力セットが用意されます。
分類器を訓練したのと同じデータセットでテストすることはない。
モデルはすでにこのデータセットのパターンを学習しており、極端な偏りが生じてしまうからだ。
その代わり、データセットをトレーニングセットとテストセットに分割し、分類器がトレーニングするセットと分類器が見たこともないセットにします。
クラシファイヤー(分類器)の種類
Credit: CreativeMagic
Scikit-Learnでは、数多くの異なる分類アルゴリズムに簡単にアクセスすることができます。
これらの分類器の中には、以下のようなものがあります。
- K-最近傍
- サポートベクターマシン
- 決定木分類器/ランダムフォレスト
- ナイーブ・ベイズ
- 線形判別分析
- ロジスティック回帰
これらの様々な分類法がどのように機能するかについては多くの文献があり、Scikit-Learnのウェブサイトでも簡単な説明を見ることができます。
このため、ここではその仕組みについてあまり深く掘り下げることはしませんが、分類器の動作についての簡単な説明はあります。
K-最近傍探索法
Credit: Antti Ajanki AnAj
K-Nearest Neighborsは、あるテスト例とある学習例の既知の値との距離をチェックすることで動作します。
訓練点とテスト点の間の距離が最も小さくなるデータ点/クラスのグループが、選択されるクラスである。
決定木
決定木分類器は、データセットを異なる基準でより小さなサブセットに分割することで機能します。
データセットを分割するために、異なるソート基準が使用され、分割ごとに例の数は少なくなっていく。
ネットワークがデータを1つの例まで分割すると、その例はキーに対応するクラスに入れられる。
複数のランダムフォレスト分類器を連結したものをランダムフォレスト分類器と呼ぶ。
ナイーブベイズ
ナイーブベイズ分類器は、ある入力イベントが発生した場合に、そのイベントが発生する確率を計算することで、ある例があるクラスに属する確率を決定します。
この計算を行うとき,クラスのすべての予測変数が結果に同じ効果を持つこと,つまり予測変数が独立であることが仮定される.
線形判別分析
線形判別分析は、データセットの次元を減らし、すべてのデータ点を線上に投影することで機能する。
そして、選択された点またはセントロイドからの距離に基づいて、これらの点をクラスに結合する。
線形判別分析は、ご推察の通り、線形分類アルゴリズムであり、データが線形関係を持つ場合に最もよく使われます。
サポートベクターマシン
クレジット Qluong2016
サポートベクターマシンは、データポイントの異なるクラスタの間に線を引いて、それらをクラスにグループ化することで機能します。
線の片側にある点はあるクラスに属し、反対側にある点は別のクラスに属します。
分類器は、どの点がどのクラスに属するかの信頼度を高めるために、引いた線とその両側の点の間の距離を最大にしようとします。
テストポイントがプロットされたとき、それらが該当する線の側が、それらが置かれるクラスである。
ロジスティック回帰
ロジスティック回帰は、テストデータ点に関する予測を0か1の2値で出力します。
0.5以上であればクラス1に、0.5以下であれば0に属すると分類される。
それぞれの特徴量も0か1かのみのラベルを持つ。
ロジスティック回帰は線形分類法であるため、データ間に何らかの線形関係がある場合に使用される。
分類タスクの例
分類タスクは、例を2つ以上のクラスに分類するタスクです。
ある画像が猫か犬かを判断するのも分類タスクですし、酸度やアルコール度などの特徴からワインの品質を判断するのも分類タスクです。
分類タスクに応じて、異なる分類器を使用する必要があります。
例えば、ロジスティック回帰モデルは、多変量ロジスティック回帰モデルもありますが、2値分類タスクに最も適しています。
分類器の使用経験を重ねるうちに、いつどの分類器を使うべきか、より良いセンスを身につけることができるでしょう。
しかし、一般的には、複数の分類器をインスタンス化して、それぞれの性能を比較し、最も性能のよい分類器を選択する方法がとられています。
分類器の実装
Scikit-Learn が提供するさまざまな分類器について説明しましたが、次は分類器を実装する方法を見ていきましょう。
分類器を実装するための最初のステップは、必要な分類器を Python にインポートすることです。
ここでは、ロジスティック回帰のimport文を見てみましょう。
from sklearn.linear_model import LogisticRegression
以下は、この記事で取り上げた他の分類器のインポート文です。
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
Scikit-Learnには他の分類器もあり、それぞれのドキュメントページでインポート方法を説明します。
この後、分類器をインスタンス化する必要があります。
インスタンス化とは、Python のプログラムの中で分類器を存在させることであり、分類器/オブジェクトのインスタンスを作成することです。
これは通常、変数を作成し、分類器に関連付けられた関数を呼び出すことで行われます。
logreg_clf = LogisticRegression()
ここで,分類器を学習する必要があります.そのためには,学習データに対して分類器を適合させる必要があります.
学習特徴量と学習ラベルは, fit
コマンドによって分類器に渡されます.
logreg_clf.fit(features, labels)
学習データに対する分類器の学習が完了すると,テストデータに対する予測を行うことができます.
これは、分類器に対して predict コマンドを呼び出し、予測を行うために必要なパラメータ(テストデータセットの特徴量)を与えることで簡単に行うことができます。
logreg_clf.predict(test_features)
これらのステップ:インスタンス化、フィット/トレーニング、予測は、Scikit-Learnにおける分類器の基本的なワークフローです。
しかし、分類器の取り扱いは、Scikit-Learnで分類を行う際の一部分に過ぎません。
Scikit-Learnでの分類の残り半分は、データのハンドリングです。
分類器の取り扱いとデータの取り扱いがどのように組み合わさって全体の分類作業となるのかを理解するために、機械学習パイプラインを少し理解しましょう。
機械学習パイプライン
機械学習のパイプラインは,データの準備,学習/テストセットの作成,分類器のインスタンス化,分類器の学習,予測,性能評価,パラメータの調整,というステップで構成されています.
分類器をデータセットで学習させる最初のステップは、データセットを準備することです。
データを分類器にとって正しい形に整え、データ中の異常な部分を処理します。
データに欠損値がある場合、データの外れ値がある場合、その他の異常がある場合、これらのデータポイントは分類器の性能に悪影響を与える可能性があるため、処理する必要があります。
このステップはデータプリプロセスと呼ばれます。
データの前処理が完了したら、データをトレーニングセットとテストセットに分割する必要があります。
トレーニングセットとテストセットを作成する根拠については前述しましたが、これは Scikit-Learn の train_test_split という便利な関数で簡単に行うことができます。
前述したように、分類器はインスタンス化され、トレーニングデータでトレーニングされる必要があります。
この後、分類器を用いて予測を行うことができます。
仮想的なラベルと実際のラベルを比較して分類器を評価する方法には,さまざまなものがあります.これらの評価指標については、後で詳しく説明します。
今のところ、分類器の精度を測定した後は、おそらく納得のいく精度になるまでモデルのパラメータを調整することになるでしょう(分類器が最初の実行で期待に応えることはまずないでしょうから)。
それでは、データ処理から評価までの機械学習パイプラインの一例を見てみましょう。
サンプル分類の実装
# Begin by importing all necessary libraries
import pandas as pd
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
虹彩のデータセットは非常に一般的なので、実はScikit-Learnにはすでにあり、以下のコマンドで読み込むことが可能です。
sklearn.datasets.load_iris
しかし、ここではCSVファイルをロードすることで、データのロードと前処理の方法を確認することができます。
csvファイルはこちらからダウンロードできます。
データファイルはPythonのファイルと同じディレクトリに置くだけです。
Pandasライブラリには、データを読み込むための簡単な方法として read_csv()
があります。
data = pd.read_csv('iris.csv')
# It is a good idea to check and make sure the data is loaded as expected.
print(data.head(5))
データセットがうまく準備されているので、多くの前処理をする必要はありません。
しかし、ひとつだけやっておきたいことがあります。
それは、”ID” カラムを削除することです。
これは役に立たないので、drop()
関数を使ってデータセットから削除することができます。
data.drop('Id', axis=1, inplace=True)
次に、特徴とラベルを定義する必要があります。
Pandasではデータテーブルをスライスし、 iloc()
を使って特定の行や列を選択することで簡単に行うことができます。
# Pandas ".iloc" expects row_indexer, column_indexer
X = data.iloc[:,:-1].values
# Now let's tell the dataframe which column we want for the target/labels.
y = data['Species']
上記のスライス表記は、最後の列(これは我々のラベルである種です)以外のすべての行と列を選択します。
あるいは、ブラケット記法を用いて列のヘッダーを渡すことで、興味のあるデータセットの特定の特徴を選択することができる。
# Alternate way of selecting columns:
X = data.iloc['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm']
欲しい特徴とラベルが揃ったので、sklearn の便利な機能 train_test_split()
を使ってデータをトレーニングセットとテストセットに分けることができます。
# Test size specifies how much of the data you want to set aside for the testing set.
# Random_state parameter is just a random seed we can use.
# You can use it if you'd like to reproduce these specific results.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=27)
データが期待通りに解析されていることを確認するために、結果を表示することもできます。
print(X_train)
print(y_train)
これでモデルのインスタンスを作成することができます。
ここでは、サポートベクトル分類器とK-最近傍分類器の2つの分類器を使ってみましょう。
SVC_model = svm.SVC()
# KNN model requires you to specify n_neighbors,
# the number of points the classifier will look at to determine what class a new point belongs to
KNN_model = KNeighborsClassifier(n_neighbors=5)
それでは、分類器をフィットさせてみましょう。
SVC_model.fit(X_train, y_train)
KNN_model.fit(X_train, y_train)
この呼び出しでモデルの学習が完了しましたので、次は予測を行い、その予測を変数に格納します。
SVC_prediction = SVC_model.predict(X_test)
KNN_prediction = KNN_model.predict(X_test)
ここで、分類器がどのように動作したかを評価する必要があります。
分類器の性能を評価する方法は複数あり、それぞれの方法については後述します。
Scikit-Learnでは、テストラベルに格納されたグランドトゥルースラベルに対する予測値を渡すだけです。
# Accuracy score is the simplest way to evaluate
print(accuracy_score(SVC_prediction, y_test))
print(accuracy_score(KNN_prediction, y_test))
# But Confusion Matrix and Classification Report give more details about performance
print(confusion_matrix(SVC_prediction, y_test))
print(classification_report(KNN_prediction, y_test))
参考までに、メトリクスの出力は以下の通りです。
SVC accuracy: 0.9333333333333333
KNN accuracy: 0.9666666666666667
一見すると、KNNの方が性能が良いように見えます。
以下はSVCの混同行列です。
[[ 7 0 0]
[ 0 10 1]
[ 0 1 11]]
これは少し解釈が難しいのですが、各クラスの正しい予測数は左上から右下への対角線上にあります。
これについては、以下をご覧ください。
最後に、KNNの分類レポートの出力です。
precision recall f1-score support
Iris-setosa 1.00 1.00 1.00 7
Iris-versicolor 0.91 0.91 0.91 11
Iris-virginica 0.92 0.92 0.92 12
micro avg 0.93 0.93 0.93 30
macro avg 0.94 0.94 0.94 30
weighted avg 0.93 0.93 0.93 30
分類器の評価
分類器の評価に関しては、そのパフォーマンスを測定するいくつかの異なる方法があります。
分類精度
分類精度は,精度を評価するすべての手法の中で最も単純であり,最もよく使われる.分類精度は、単純に正しい予測の数をすべての予測で割ったもの、または正しい予測の比率を全体の予測で割ったものです。
これは、分類器がどのように動作しているかをすばやく知ることができますが、各クラスにおけるオブザベーション/サンプルの数がほぼ等しいときに最もよく使われます。
このようなことはあまり起こらないので、おそらく他の指標を使用したほうがよいでしょう。
対数損失
Logarithmic Loss (LogLoss) は,本質的に分類器の予測に対する信頼度を評価します.LogLoss は,分類器の一般的な信頼度を表現するために,与えられたクラスにおける例のメンバーシップに対する確率を返し,それらを合計します.
予測値の値は1から0まであり,1が完全に信頼できる,0が信頼できないことを表します.損失、つまり全体的な自信のなさは負の数で返され、0 は完全な分類器を表すので、値は小さい方がよいでしょう。
ROC曲線下面積(AUC)
これは2値分類問題のみに使用される指標である。
曲線の下の面積は、モデルが否定的な例と肯定的な例の間、つまり1つのクラスと別のクラスの間を適切に識別する能力を表します。
1.0は,すべての面積が曲線の下に位置し,完全な分類器を表します.つまり、AUCが0.5であれば、基本的にランダムに推測しているのと同じであることを意味する。
ROC曲線は、感度(真陽性率/再現率)と特異度(真陰性率)に関して計算される。
これらの計算については、こちらのROC曲線の記事で詳しく解説しています。
コンフュージョンマトリックス
混同行列は、2つ以上のクラスに関するモデルの精度を表す表またはグラフである。
モデルの予測はX軸に、結果/精度はY軸に配置される。
セルは、モデルが行った予測の数で埋められます。
正しい予測は、左上から右下に向かう対角線上に見つけることができます。
混同行列の解釈について、詳しくはこちらをご覧ください。
クラシフィケーションレポート
分類レポートは、分類問題のために特別に作成されたScikit-Learn組み込みのメトリックです。
分類レポートを使用することで、モデルがどのように機能しているかを素早く直感的に理解することができます。
Recallは、クラスAの例の総数に対して、モデルがクラスA(ある与えられたクラス)としてラベル付けした例の数を比較し、これをレポートに表現します。
レポートでは予測値とf1-scoreも返されます。
精度は、あなたのモデルがクラスAとしてラベル付けした例のうち、実際にクラスAに属していた割合(偽陽性に対する真陽性)であり、f1-scoreは精度とリコールの平均値である。
結論
Scikit-Learnをより深く理解するために、利用可能なさまざまな分類アルゴリズムについて学ぶとよいでしょう。
これらのアルゴリズムを理解したら、分類器の評価方法についても読んでみてください。
分類のニュアンスの多くは時間と練習によってのみ得られるものですが、このガイドのステップに従えば、Scikit-Learnを使った分類タスクのエキスパートになる道が開けるでしょう。