55
Python 機械学習プログラミング 第 3 分類問題 機械学習ライブラリ scikit-learn の活用 内山 雄司 (@y__uti) 2017-05-18 社内勉強会

分類問題 - 機械学習ライブラリ scikit-learn の活用

  • Upload
    y-uti

  • View
    3.137

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 分類問題 - 機械学習ライブラリ scikit-learn の活用

Python 機械学習プログラミング 第 3 章

分類問題― 機械学習ライブラリ scikit-learnの活用

内山 雄司 (@y__uti)

2017-05-18 社内勉強会

Page 2: 分類問題 - 機械学習ライブラリ scikit-learn の活用

自己紹介内山雄司 (@y__uti)

◦ http://y-uti.hatenablog.jp/ (phpusers-ja)

仕事◦ 受託開発の会社 (株式会社ピコラボ) でプログラマをしています

興味◦ プログラミング言語処理系

◦ 機械学習

2017-05-18 社内勉強会 2

Page 3: 分類問題 - 機械学習ライブラリ scikit-learn の活用

この章で学ぶこと1. scikit-learn を使ってみる

2. さまざまな分類アルゴリズムを試してみる◦ パーセプトロン

◦ ロジスティック回帰

◦ サポートベクトルマシン

◦ 決定木

◦ k 近傍法

2017-05-18 社内勉強会 3

Page 4: 分類問題 - 機械学習ライブラリ scikit-learn の活用

データの準備3.2 sc ik it- learn を使ったパーセプトロンのトレーニング

2017-05-18 社内勉強会 4

Page 5: 分類問題 - 機械学習ライブラリ scikit-learn の活用

Iris データセット

2017-05-18 社内勉強会 5

「あやめ」の 3 品種 150 サンプルからなるデータセット◦ データベースでいうところのテーブルだと思えばよい

◦ 150 行のレコードがあるということ

各サンプルは以下の情報 (カラムだと思えばよい) を持つ◦ がく片の長さ sepal length

◦ がく片の幅 sepal width

◦ 花びらの長さ petal length

◦ 花びらの幅 petal width

◦ 品種 class

◦ Iris-Setosa

◦ Iris-Versicolor

◦ Iris-Virginica

Page 6: 分類問題 - 機械学習ライブラリ scikit-learn の活用

我々の目的あやめの品種を判別する関数を作りたい

引数◦ 花びらの長さ

◦ 花びらの幅

戻り値◦ 品種

2017-05-18 社内勉強会 6

def predict(petal_length, petal_width):...return iris_class

データを睨みながら職人芸で実装するのではなく

データから自動的にルールを見つけ出したい

Page 7: 分類問題 - 機械学習ライブラリ scikit-learn の活用

データセットの分割何のために?◦ あやめの品種を判別する関数が得られたとしましょう

◦ その関数を使って「当たった!」とか「外れた」とか遊びたい

◦ ところが手持ちのデータは全部で 150 個しかない

◦ 遊ぶためのデータを 150 個のサンプルから最初に分けておく

なぜ「分けておく」必要が? (同じデータでは駄目?)

◦ 関数を作るときに使ったデータを判別に使うと「ズル」ができる

◦ たとえば丸暗記

2017-05-18 社内勉強会 7

Page 8: 分類問題 - 機械学習ライブラリ scikit-learn の活用

層化抽出法手持ちのデータは 3 品種それぞれ 50 サンプル

教科書の方法で分割すると各品種の比率は維持されない

2017-05-18 社内勉強会 8

>>> from collections import Counter>>> sorted(Counter(y_train).items())[(0, 34), (1, 32), (2, 39)]

層化抽出法:母集団の比率を維持してサンプリングする◦ train_test_split 関数の stratify オプション

>>> X_train, ... = train_test_split(X, y, ..., stratify=y)

>>> sorted(Counter(y_train).items())[(0, 35), (1, 35), (2, 35)]

Page 9: 分類問題 - 機械学習ライブラリ scikit-learn の活用

特徴量のスケーリング何のために?◦ アルゴリズムそのものに由来する問題

◦ コンピュータでの計算上の都合

具体的には・・・1. 特徴量が不揃いだと良い結果を得られないアルゴリズムがある

◦ たとえば k 近傍法 (距離の定義による)

2. 特徴量が不揃いだと遅くなるアルゴリズムがある◦ たとえばパーセプトロン (パーセプトロンの収束定理)

3. 特徴量が不揃いだと数値計算上の問題を招くアルゴリズムがある◦ たとえばサポートベクトルマシン

◦ see sec. 2.2 in "A Practical Guide to Support Vector Classification"

◦ https://www.csie.ntu.edu.tw/~cjlin/papers/guide/guide.pdf

2017-05-18 社内勉強会 9

Page 10: 分類問題 - 機械学習ライブラリ scikit-learn の活用

標準化データを次の操作で変換する1. 平均が 0 になるように平行移動する

2. 標準偏差が 1 になるように定数倍する

2017-05-18 社内勉強会 10

>>> X_train_tmp = X_train - np.mean(X_train, 0)>>> X_train_std = X_train_tmp / np.std(X_train_tmp, 0)

Page 11: 分類問題 - 機械学習ライブラリ scikit-learn の活用

テストデータの標準化トレーニングデータと「同じ値だけ」動かす

2017-05-18 社内勉強会 11

>>> X_test_tmp = X_test - np.mean(X_train, 0)>>> X_test_std = X_test_tmp / np.std(X_train, 0)

Page 12: 分類問題 - 機械学習ライブラリ scikit-learn の活用

パーセプトロン3.2 sc ik i t - learn を使ったパーセプトロンのトレーニング

2017-05-18 社内勉強会 12

Page 13: 分類問題 - 機械学習ライブラリ scikit-learn の活用

パーセプトロンアルゴリズムの説明は第 2 章で既出なので省略

実装と実行手順も教科書のとおりなので省略

2017-05-18 社内勉強会 13

Page 14: 分類問題 - 機械学習ライブラリ scikit-learn の活用

One vs Rest classifier二クラス分類器を使って多クラス分類を実現する方法の一つ

例:Iris データセットの場合

次の 3 個の二クラス分類器を学習する1. Setosa か「それ以外」か⇒判別関数の値が正なら Setosa

2. Versicolor か「それ以外」か⇒判別関数の値が正なら Versicolor

3. Virginica か「それ以外」か⇒判別関数の値が正なら Virginica

多クラス分類の方法◦ 学習した 3 個の分類器でそれぞれ判別関数の値を求める

◦ 判別関数の値が最大となったクラスを採用する◦ 個々の値を見れば「全て正」や「全て負」になっているかもしれないが気にしない

2017-05-18 社内勉強会 14

Page 15: 分類問題 - 機械学習ライブラリ scikit-learn の活用

パーセプトロンの学習率パーセプトロンでは学習率を調整する必要はない◦ この点に関する教科書の記述は誤り

◦ eta0 の既定値は 1.0 であり既定値のまま使えばよい

参考 (他の教科書など)

◦ 『パターン認識と機械学習』4.1.7 パーセプトロンアルゴリズム◦ "一般性を失うことなく学習率パラメータ τ を 1 に設定することができる" (p. 192)

◦ 『オンライン機械学習』アルゴリズム 3.1 (p. 24)

◦ アルゴリズムを説明した擬似コードに学習率は表れない

◦ Perceptron - Wikipedia

◦ https://en.wikipedia.org/wiki/Perceptron

◦ "Learning Algorithm" の記述に学習率は表れない

◦ scikit-learn の API ドキュメント

◦ http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Perceptron.html

◦ eta0 の既定値が 1.0 であることを確認できる

2017-05-18 社内勉強会 15

Page 16: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ロジスティック回帰3.3 ロジスティック回帰を使ったクラスの確率のモデリング

2017-05-18 社内勉強会 16

Page 17: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ロジスティック回帰の結果教科書のコード例と同じ設定での実行結果

◦ C = 1000

◦ 一対他の手法で多クラス分類を実現 (パーセプトロンと同じ)

2017-05-18 社内勉強会 17

Page 18: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ロジスティック回帰 [1/4]例:virginica と「それ以外」を分類

まずは特徴量の重み付け和を考える (パーセプトロンと同じ)

2017-05-18 社内勉強会 18

z = 2.0 * petal_length - 1.5 * petal_width - 0.2

Page 19: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ロジスティック回帰 [2/4]例:virginica と「それ以外」を分類

シグモイド関数を用いて 0 ~ 1 の範囲に押し込める

2017-05-18 社内勉強会 19

phi = 1.0 / (1.0 + np.exp(-z))

Page 20: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ロジスティック回帰 [3/4]例:virginica と「それ以外」を分類

コスト関数 (= 分類のはずれ具合の総和) を考える

2017-05-18 社内勉強会 20

J = np.sum(-y * np.log(phi(z)) - (1-y) * np.log(1-phi(z)))

J = 59.78

Page 21: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ロジスティック回帰 [4/4]例:virginica と「それ以外」を分類

コスト関数を小さくする方向に重みベクトルを更新する

2017-05-18 社内勉強会 21

z = 1.0 * petal_length + 1.0 * petal_width - 1.0

J = 27.94

Page 22: 分類問題 - 機械学習ライブラリ scikit-learn の活用

正則化正則化とは?◦ モデルの複雑さを抑えるテクニック

◦ 具体的には「重みベクトルの大きさに応じたペナルティ」を足す

何のために?◦ パラメータ数が多いと過学習が発生する

◦ そういうモデルはテストデータを予測できない

(たぶん) よく使われる「ペナルティ」の種類◦ L2 正則化 重みベクトルの大きさの二乗に比例

◦ L1 正則化 重みベクトルの大きさに比例

◦ elasticnet L2 + L1

2017-05-18 社内勉強会 22

Page 23: 分類問題 - 機械学習ライブラリ scikit-learn の活用

コストパラメータ [1/2]コスト関数 (= 分類のはずれ具合の総和) に掛ける係数◦ 小さな値に設定⇒重みベクトルを小さくすること (正則化項) を重視

◦ 大きな値に設定⇒学習データを分類することを重視

2017-05-18 社内勉強会 23

Page 24: 分類問題 - 機械学習ライブラリ scikit-learn の活用

コストパラメータ [2/2]ロジスティック回帰の場合◦ 下図は petal length = petal width に沿って動かしたときの様子

◦ Versicolor (橙) は殆ど変化しない。他の分類器の影響で結果が変わる

2017-05-18 社内勉強会 24

Page 25: 分類問題 - 機械学習ライブラリ scikit-learn の活用

線形 SVM3.4 サポートベクトルマシンによる最大マージン分類

2017-05-18 社内勉強会 25

Page 26: 分類問題 - 機械学習ライブラリ scikit-learn の活用

SVM の概要決定境界のなかで一番「幅を広く」できるものを求める◦ どうやってそんなことが!

◦ 難しいので説明しないがとにかくできる

下図は Setosaと「それ以外」を二値分類した様子◦ 中央が SVM で得られる結果

2017-05-18 社内勉強会 26

Page 27: 分類問題 - 機械学習ライブラリ scikit-learn の活用

SVM のコスト関数(導出過程はさておき) 結果として SVM は◦ 「ヒンジ損失 + L2 正則化」をコスト関数として最適化する

いろいろな損失関数 (右図)

◦ 青:パーセプトロン

◦ 橙:ロジスティック回帰

◦ 緑:ヒンジ損失

2017-05-18 社内勉強会 27

Page 28: 分類問題 - 機械学習ライブラリ scikit-learn の活用

線形 SVM の実行結果教科書のコード例と同じ設定での実行結果

2017-05-18 社内勉強会 28

>>> svm = SVC(kernel='linear', C=1.0, random_state=0)

◦ scikit-learn の SVC は libsvm を利用する

◦ https://www.csie.ntu.edu.tw/~cjlin/libsvm/

Page 29: 分類問題 - 機械学習ライブラリ scikit-learn の活用

LinearSVCでの実行結果線形 SVM での分類には LinearSVCも利用できる

2017-05-18 社内勉強会 29

>>> svm = LinearSVC(random_state=0)

◦ LinearSVCは liblinear を利用する

◦ https://www.csie.ntu.edu.tw/~cjlin/liblinear/

Page 30: 分類問題 - 機械学習ライブラリ scikit-learn の活用

SGDClassifier一括学習 (batch learning)

◦ すべての学習データを読み込んでから学習する

◦ LogisticRegression, SVC, LinearSVCはこちら◦ 内部で利用している libsvm や liblinear が一括学習のため

◦ LogisticRegression は solver を選べる。solver='liblinear' がデフォルト

逐次学習 (online learning)

◦ 学習データを一つずつ使って学習する

◦ Perceptron はこちら (教科書の記述は誤り)

◦ 確率的勾配降下法 (Stochastic Gradient Descent)

◦ http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html

◦ データ量が多い場合やストリームで供給される場合などに有用

2017-05-18 社内勉強会 30

Page 31: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM3.5 カーネル SVM を使った非線形問題の求解

2017-05-18 社内勉強会 31

Page 32: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM の威力 [1/4]以下のようなデータを考える◦ 左図:X と Y の符号が同じなら 0, 符号が異なっていたら 1

◦ 右図:原点からの距離の 2 乗が 2 未満なら 0, 2 以上なら 1

2017-05-18 社内勉強会 32

Page 33: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM の威力 [2/4]このようなデータは線形分離不可能◦ 下図は線形 SVM を適用して学習した結果

◦ まともに動かない

2017-05-18 社内勉強会 33

Page 34: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM の威力 [3/4]カーネル SVM を適用する◦ 下図は「二次の多項式カーネル」を用いて学習した結果

◦ なんだこれは!

2017-05-18 社内勉強会 34

Page 35: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM の威力 [4/4]カーネル SVM を適用する◦ 下図は「RBF カーネル」を用いて学習した結果

◦ なんだこれは!

2017-05-18 社内勉強会 35

Page 36: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVMの概要 [1/2]次の二つのアイデアの組み合わせ1. 特徴量を「水増し」して高次元空間で線形分類する

2. 本当に水増しするのではなく「カーネル関数」で効率的に計算する

特徴量の水増し◦ 元々の特徴量が 2 種類 (x1, x2) だったら・・・

◦ 2 次の項を追加すれば 5 種類

◦ x1*x1

◦ x1*x2

◦ x2*x2

◦ 3 次の項も追加すれば 9 種類

◦ x1*x1*x1

◦ x1*x1*x2

◦ x1*x2*x2

◦ x2*x2*x2

2017-05-18 社内勉強会 36

2 次の項を入れた 5 次元空間ならこれらはアッサリ分類できる

Page 37: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM の概要 [2/2]次の二つのアイデアの組み合わせ1. 特徴量を「水増し」して高次元空間で線形分類する

2. 本当に水増しするのではなく「カーネル関数」で効率的に計算する

カーネル関数◦ 単純に特徴量を増やすと次元の数が爆発して実用にならない

◦ 重みベクトルとの内積さえ計算できればよい

例:2 次の多項式カーネル (本当はもう少し細かなパラメータがあります)

2017-05-18 社内勉強会 37

z = (1 + w1*x1 + w2*x2)^2= 1 + 2 * w1 * x1

+ 2 * w2 * x2+ w1*w1 * x1*x1+ 2 * w1*w2 * x1*x2+ w2*w2 * x2*x2

このスライドは色々と間違えています

Page 38: 分類問題 - 機械学習ライブラリ scikit-learn の活用

カーネル SVM の実行結果教科書のコード例と同じ設定での実行結果

◦ kernel = 'rbf'

◦ gamma = 0.2

◦ C = 1.0

2017-05-18 社内勉強会 38

Page 39: 分類問題 - 機械学習ライブラリ scikit-learn の活用

gamma, C による変化 [1/2]

2017-05-18 社内勉強会 39

Page 40: 分類問題 - 機械学習ライブラリ scikit-learn の活用

gamma, C による変化 [2/2]

2017-05-18 社内勉強会 40

Page 41: 分類問題 - 機械学習ライブラリ scikit-learn の活用

決定木3.6 決定木学習

2017-05-18 社内勉強会 41

Page 42: 分類問題 - 機械学習ライブラリ scikit-learn の活用

決定木のアルゴリズムIf-else のネスト構造でデータを判別する

2017-05-18 社内勉強会 42

if petal_width <= 0.75:return 0 # Iris-Setosa

else:if petal_length <= 4.95:

return 1 # Iris-Versicolorelse:

return 2 # Iris-Virginica

分岐条件をどのように決めるか?◦ 各クラスが then, else に「なるべく綺麗に分かれる」条件を探す

◦ ジニ不純度

◦ エントロピー

Page 43: 分類問題 - 機械学習ライブラリ scikit-learn の活用

決定木の実行結果max_depth = 3 での実行結果◦ criterion='entropy' で実行 (教科書と同じ)

◦ デフォルトは criterion='gini'

2017-05-18 社内勉強会 43

Page 44: 分類問題 - 機械学習ライブラリ scikit-learn の活用

木の深さによる結果の変化

2017-05-18 社内勉強会 44

Page 45: 分類問題 - 機械学習ライブラリ scikit-learn の活用

エントロピー情報理論の何やら難しい概念◦ ここでは「各クラスのサンプルの混ざり具合い」だと思えばよい

2017-05-18 社内勉強会 45

def entropy(counts):return np.sum([

-p * np.log2(p) if p > 0 else 0for p in counts / np.sum(counts)])

>>> print(entropy([50, 50, 50])) # 1.58496250072>>> print(entropy([20, 30, 50])) # 1.48547529723>>> print(entropy([ 0, 30, 50])) # 0.954434002925>>> print(entropy([ 0, 10, 50])) # 0.650022421648>>> print(entropy([ 0, 0, 50])) # 0.0

◦ -p * log2(p) は p = 0 で計算不能だが +0 の極限が 0 なので 0 とする

Page 46: 分類問題 - 機械学習ライブラリ scikit-learn の活用

閾値ごとのエントロピー

2017-05-18 社内勉強会 46

Page 47: 分類問題 - 機械学習ライブラリ scikit-learn の活用

ランダムフォレスト次の方法で「雑な」決定木をたくさん作って多数決で判別する

1. トレーニングデータの一部をランダムに取り出す (復元抽出)

2. 取り出したデータだけを使って決定木を作る◦ 各ノードで分割するときには特徴量の一部をランダムに取り出す

◦ 取り出した特徴量だけを候補にして分割の閾値を決める

2017-05-18 社内勉強会 47

Page 48: 分類問題 - 機械学習ライブラリ scikit-learn の活用

k 近傍法3.7 k 近傍法:怠惰学習アルゴリズム

2017-05-18 社内勉強会 48

Page 49: 分類問題 - 機械学習ライブラリ scikit-learn の活用

k 近傍法のアルゴリズム学習データセットを丸ごと保持する

次の手順で判別する1. 最も近い k 個のデータを探す

2. その k 個の多数決で決める

Iris データセットでの例 (右図)

◦ k = 5

◦ 座標 (0.5, 0.55) の品種を判別

◦ Versicolor 3 個 vs. Virginica 2 個

◦ Versicolor と判別する

2017-05-18 社内勉強会 49

Page 50: 分類問題 - 機械学習ライブラリ scikit-learn の活用

k 近傍法の実行結果k = 5 での実行結果◦ 距離尺度は metric='euclidean' で実行

◦ 教科書に書かれている metric='minkowsky', p=2 と同じ

2017-05-18 社内勉強会 50

Page 51: 分類問題 - 機械学習ライブラリ scikit-learn の活用

k の値による結果の変化

2017-05-18 社内勉強会 51

Page 52: 分類問題 - 機械学習ライブラリ scikit-learn の活用

多数決が同数の場合 [1/2]scikit-learn の実装では「クラスの順序」に依存する◦ scipy.stats.modeを利用しているため

◦ 教科書 91 ページの囲みの記述は誤り

参考◦ scikit-learn の実装

◦ https://github.com/scikit-learn/scikit-learn/blob/0.18/sklearn/neighbors/classification.py

◦ scipy.stats.modeのドキュメント

◦ https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.stats.mode.html

weights='distance' パラメータ

◦ "weight points by the inverse of their distance"

◦ これは「多数決が同数の場合に距離が近いものを優先」ではない

2017-05-18 社内勉強会 52

Page 53: 分類問題 - 機械学習ライブラリ scikit-learn の活用

多数決が同数の場合 [2/2]人工的なデータに k 近傍法を適用した結果

2017-05-18 社内勉強会 53

Page 54: 分類問題 - 機械学習ライブラリ scikit-learn の活用

metric パラメータデータによってはユークリッド距離では「近さ」を測れない◦ 緯度経度で表されたデータ

◦ booleanを要素とするデータ

データ間の距離を計算する方法を指定できる

参考

◦ sklearn.neighbors.DistanceMetric

◦ http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.DistanceMetric.html

2017-05-18 社内勉強会 54

Page 55: 分類問題 - 機械学習ライブラリ scikit-learn の活用

おわり

2017-05-18 社内勉強会 55