English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Pythonの決定木分類アルゴリズムの学習

この章から正式なアルゴリズムの学習に入ります。

まず、古典的かつ効果的な分類アルゴリズムを学びます:決定木分類アルゴリズム。

1、決定木アルゴリズム

決定木はサンプルの属性を分類するための樹形構造を使用し、最も直感的な分類アルゴリズムの一つです。また、回帰にも使用できます。しかし、特殊な論理分類には難しい場合があります。典型的な例としてXOR(XOR)論理があり、決定木はこのような問題を解決するのに適していないです。
決定木の構築は一意ではありません。残念ながら最適な決定木の構築はNP問題です。したがって、良い決定木の構築方法は研究の重点です。
J. Ross Quinlanは、1975は情報エントロピーの概念を決定木の構築に導入することを提唱しました。これが有名なID3アルゴリズム。後のC4.5, C5.0、CARTなどはこの方法の改良です。

エントロピーは「無秩序、混乱」の程度を示します。この概念に初めて触れると少し困惑するかもしれません。情報エントロピーの増加を利用して属性を分割する方法を速やかに理解するには、この兄弟の記事を参照してください:Python機械学習の決定木アルゴリズム

まだ理解できない場合は、以下の例を参照してください。

自動的に良いリンゴを選ぶ決定木を構築する必要があると仮定すると、簡単にするために、以下のものだけを学習させます:4個のサンプル:
サンプル  赤  大  好リンゴ 
0         1        1         1 
1         1        0         1 
2         0        1         0 
3         0        0         0 

サンプルには2個の属性があります。A0はリンゴが赤であるかどうかを示しています。A1大リンゴであるかどうかを示しています。

したがって、このサンプルが分類前の情報エントロピーはS = -(1/2 * log(1/2) + 1/2 * log(1/2)) = 1。

情報エントロピーは1現在が最も混乱し、最も無秩序な状態を示しています。

本例では、2個の属性があります。したがって、自然と合計でたった2本の決定木が優れています。以下の図に示されています:

明らかに、左側がA0(赤色)を分割基準とする決定木は、右側がA1(大きさ)を分割基準とする決定木です。
もちろん、これは直感的な認識です。定量的な考察をするには、各分割状況の情報エントロピーの増加を計算する必要があります。
まずA0を分割基準として選択し、各子ノードの情報エントロピーの計算は以下の通りです:
0、1葉ノードには2個の正例、0個の負例があります。情報エントロピーは:e1 = -(2/2 * log(2/2) + 0/2 * log(0/2)) = 0。
2、3葉ノードには0個の正例があります。2負例が2 = -(0/2 * log(0/2) + 2/2 * log(2/2)) = 0。

したがって、A0分割後の情報エントロピーは各子ノードの情報エントロピーが重み付けされた和です:E = e1*2/4 + e2*2/4 = 0。
A0を分岐する情報エントロピーの増加 G(S, A0)=S - E = 1 - 0 = 1.

実際には、決定木の葉ノードは既に同じカテゴリに属していることを示しており、したがって情報エントロピーは必ず0です。

同様に、Aを選択する場合も1の分岐を行い、各子ノードの情報エントロピーは以下のように計算されます:
0、2子ノードが1正例が1負例が1 = -(1/2 * log(1/2) + 1/2 * log(1/2)) = 1。
1、3子ノードが1正例が1負例が2 = -(1/2 * log(1/2) + 1/2 * log(1/2)) = 1。
したがってAを選択1分割後の情報エントロピーは、各子ノードの情報エントロピーの重み付き平均です:E = e1*2/4 + e2*2/4 = 1。つまり、分岐しても変わらないということです!
Aを選択1情報エントロピーの増加 G(S, A)1)=S - E = 1 - 1 = 0.
したがって、分割の前に、情報エントロピーの増加が最大の分割を計算するだけで十分です。

2、データセット

説明と理解を容易にするために、以下の非常にシンプルなテストデータセットを使用します:
1.5 50 痩せている 
1.5 60 肥満 
1.6 40 痩せている 
1.6 60 肥満 
1.7 60 痩せている 
1.7 80 肥満 
1.8 60 痩せている 
1.8 90 肥満 
1.9 70 痩せている 
1.9 80 肥満 

このデータセットには10サンプルがあり、各サンプルには2属性が、身長と体重で、3列目はカテゴリラベルで、「肥満」または「痩せている」を示しています。このデータは以下のファイルに保存されています:1.txt内にあります。

私たちのタスクは、身長と体重を入力して、この人が肥満か痩せているかを分類する決定木分類器をトレーニングすることです。
(データは著者の主観的な推測であり、一定の論理性がありますが、合理性を無視してください)

決定木は「はい」「いいえ」の二値論理の分岐が非常に自然です。では、本データセットでは身長と体重が連続値の場合はどうですか?

少し面倒ですが、それも問題ではありません。これらの連続値を異なる区間に分割する中間点を見つければ、二値論理の問題に変換できます。
この例では、決定木のタスクは身長、体重の一部の閾値を見つけ、これらの閾値を超えるかどうかの論理に基づいてサンプルを二分類し、上から下へ決定木を構築することです。

Pythonの機械学習ライブラリを使用すると、実装は非常にシンプルでエレガントです。

3、Pythonの実装

以下はPythonコードの実装です:

# -*- coding: utf-8 -*- 
import numpy as np 
import scipy as sp 
from sklearn import tree 
from sklearn.metrics import precision_recall_curve 
from sklearn.metrics import classification_report 
from sklearn.cross_validation import train_test_split 
''' データ読み込み ''' 
data  = [] 
labels = [] 
with open("data\\1.txt) として ifile: 
    for line in ifile: 
      tokens = line.strip().split(' ') 
      data.append([float(tk) for tk in tokens[:-1]) 
      labels.append(tokens[-1]) 
x = np.array(data) 
labels = np.array(labels) 
y = np.zeros(labels.shape) 
'''ラベルを0に変換'''/1 ''' 
y[labels=='fat'] =1 
'''トレーニングデータとテストデータの分割''' 
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2) 
'''情報エントロピーを使用して決定木をトレーニング''' 
clf = tree.DecisionTreeClassifier(criterion='entropy') 
print(clf) 
clf.fit(x_train, y_train) 
'''決定木構造をファイルに書き込む''' 
with open("tree.dot", 'w') as f: 
  f = tree.export_graphviz(clf, out_file=f) 
'''係数は各特徴の影響力を反映しています。大きいほどその特徴が分類に果たす役割が大きいです''' 
print(clf.feature_importances_) 
'''テスト結果の印刷''' 
answer = clf.predict(x_train) 
print(x_train) 
print(answer) 
print(y_train) 
print(np.mean(answer == y_train)) 
'''正確率と召回率''' 
precision, recall, thresholds = precision_recall_curve(y_train, clf.predict(x_train)) 
answer = clf.predict_proba(x)[:1] 
print(classification_report(y, answer, target_names = ['thin', 'fat'])) 

出力結果は以下のようになります:
[ 0.2488562  0.7511438]
array([[  1.6,  60. ],
       [  1.7,  60. ],
       [  1.9,  80. ],
       [  1.5,  50. ],
       [  1.6,  40. ],
       [  1.7,  80. ],
       [  1.8,  90. ],
       [  1.5,  60. ])
array([ 1,  0.,  1,  0.,  0.,  1,  1,  1.])
array([ 1,  0.,  1,  0.,  0.,  1,  1,  1.])
1.0
             precision    recall  f1-score   support
       thin       0.83      1.00      0.91         5
        fat        1.00      0.80      0.89         5
avg / total       1.00      1.00      1.00         8
array([ 0.,  1,  0.,  1,  0.,  1,  0.,  1.  0.,  0.])
array([ 0.,  1,  0.,  1,  0.,  1,  0.,  1,  0.,  1.])

これにより、トレーニングされたデータに対してテストを行うと、正解率は100%。しかし最終的にすべてのデータをテストすると、1個のテストサンプルが分類ミスしました。
この例の決定木がトレーニングセットのルールをよく吸収していることが示されていますが、予測性は少し低いです。
ここには3点を説明します。これは将来的な機械学習でもよく使用されます。

1、トレーニングデータとテストデータの分割。

このようにすることで、クロス検証を簡単に行うことができます。クロス検証は、分類器の安定性を十分にテストするために行われます。
コード中的の0.2はランダムに取20%のデータがテスト用に使用されます。残りの80%が決定木のトレーニングに使用されます。
つまり10回のサンプルからランダムに取8回のトレーニング。このデータセットは小さいため、ここでの目的は、トレーニングデータがランダムに取られているため、每次に構築される決定木が異なることを示すことです。

2、特徴の異なる影響因子。

サンプルの異なる特徴が分類に与える影響の重みの差は大きくなります。分類が終わった後、各サンプルが分類に与える影響を確認することも非常に重要です。
この例では、身長の重みは0.25、体重が0.75、重量的な重要性は身長よりもはるかに高いことがわかります。体重と体型の判定において、これは非常に論理的です。

3、正解率と召回率。

これ2個の値は分類の正解率を評価する重要な基準です。例えばコードの最後ですべての10個のサンプルが分類器にテストされた結果:
テスト結果:array([ 0.,  1,  0.,  1,  0.,  1,  0.,  1.  0.,  0.])
実際の結果:array([ 0.,  1,  0.,  1,  0.,  1,  0.,  1,  0.,  1.])
thinに分けた正解率が0.83。なぜなら分類器は6個thinがあり、そのうち正しいのは5個あり、そのためthinに分けた正解率が5/6=0.83。
thinに分けた召回率が1.00。なぜならデータセットには5個thinがあり、分類器はそれらをすべて正しく分類した(しかし一個のfatをthinに分けた!),召回率5/5=1。
fatに分けた正解率が1.00。詳述しない。
fatに分けた召回率が0.80。なぜならデータセットには5個fatで、分類器は4個(一個fatをthinに分けた!),召回率4/5=0.80。
多くの場合、特にデータ分類が難しい場合、正確率と召回率は矛盾することがあります。あなたのニーズに応じて、最も良いバランスを見つける必要があります。
例えば、この例では、あなたの目標は、見つける肥満者が本当に肥満者であることを保証すること(正確率)か、多くの肥満者を見つけることを保証すること(召回率)です。

コードは、決定木の構造をtree.dotに書き込みます。このファイルを開くと、簡単に決定木を描画できますし、決定木の多くの分類情報も見ることができます。
本文のtree.dotは以下の通りです:

digraph Tree { 
0 [label="X[1] <= 55.0000\nentropy = 0.954434002925\nsamples = 8", shape="box"] ; 
1 [label="entropy = 0.0000\nsamples = 2\nvalue = [ 2. 0.]", shape="box"] ; 
0 -> 1 ; 
2 [label="X[1] <= 70.0000\nentropy = 0.650022421648\nsamples = 6", shape="box"] ; 
0 -> 2 ; 
3 [label="X[0] <= 1.6500\nentropy = 0.918295834054\nsamples = 3", shape="box"] ; 
2 -> 3 ; 
4 [label="entropy = 0.0000\nsamples = 2\nvalue = [ 0. 2.", shape="box"] ; 
3 -> 4 ; 
5 [label="entropy = 0.0000\nsamples = 1\nvalue = [ 1. 0.]", shape="box"] ; 
3 -> 5 ; 
6 [label="entropy = 0.0000\nsamples = 3\nvalue = [ 0. 3.", shape="box"] ; 
2 -> 6 ; 
} 

この情報に基づいて、決定木は以下のようになります:

これで本文の全てが終わりました。皆様の学習に役立てば幸いですし、ぜひ「ノートルダム教程」を多くのサポートをお願いします。

声明:本文の内容はインターネットから取得しており、著作権者に帰属します。インターネットユーザーが自発的に貢献し、自己でアップロードしたものであり、本サイトは所有権を有しておらず、人工的な編集は行われていません。著作権に関する問題がある場合は、メールを送信してください:notice#oldtoolbag.com(メールを送信する際に、#を@に置き換えてください。告発を行い、関連する証拠を提供してください。一旦確認が取れた場合、本サイトは即座に侵害が疑われる内容を削除します。)

基本チュートリアル
おすすめ