決定木について説明します

May 08 2022
この投稿では、決定木と呼ばれる一般的に使用される機械学習モデルについて説明します。デシジョンツリーは、主に説明性が高いだけでなく、セットアップとトレーニングが比較的簡単であり、デシジョンツリーを使用して予測を実行するのにかかる時間が短いため、多くのアプリケーションで好まれます。

この投稿では、決定木と呼ばれる一般的に使用される機械学習モデルについて説明します。デシジョンツリーは、主に説明性が高いだけでなく、セットアップとトレーニングが比較的簡単であり、デシジョンツリーを使用して予測を実行するのにかかる時間が短いため、多くのアプリケーションで好まれます。決定木は表形式のデータにとって自然なものであり、実際、現在、そのタイプのデータでは(画像ではなく)ニューラルネットワークよりも優れているように見えます。ニューラルネットワークとは異なり、ツリーは入力の正規化を必要としません。これは、トレーニングが最急降下法に基づいておらず、最適化するパラメーターが非常に少ないためです。値が欠落しているデータをトレーニングすることもできますが、現在、この方法はあまり推奨されておらず、欠落している値は通常、帰属されます。

デシジョンツリーのよく知られたユースケースには、レコメンデーションシステム(過去の選択やその他の機能(年齢、性別など)に基づいて予測される映画の好みは何ですか)と検索エンジンがあります。

ツリーの予測プロセスは、サンプルの属性(特徴)と事前に学習されたしきい値との一連の比較で構成されます。上(木の根)から下に向かって(葉に向かって、はい、実際の木とは反対に)、各ステップで、比較の結果によって、サンプルが木の中で左に行くか右に行くかが決まります。それによって—次の比較ステップを決定します。サンプルがリーフ(エンドノード)に到達すると、リーフの多数派クラスに基づいて決定または予測が行われます。

図1は、花びらとがく片の長さと幅に基づいて、アイリスサンプルを3つの異なる種(クラス)に分類するという問題を伴うこのプロセスを示しています。

私たちの例は、有名なアイリスデータセットに基づいています(Fisher、RA「分類学的問題における複数の測定値の使用」Annual Eugenics、7、Part II、179–188(1936))。あるクラスの機能を変更し、列車セットのサイズを小さくして、クラスを少し混ぜて、より面白くしました。

図1アイリスデータセットの修正されたトレインセットでトレーニングされた決定木。

このツリーの詳細については後で説明します。今のところ、ルートノードを調べて、トレーニング母集団に45のサンプルがあり、[13、19、13]のように3つのクラスに分けられていることに注目してください。'class'属性は、ノード内の多数派クラスに基づいて、ツリーがこのサンプルがリーフである場合に予測するラベルを示します。たとえば、比較の実行が許可されていない場合、ルートノードになり、列車セットに19個のサンプルがあるのに対し、他の2つのクラスでは13個あるため、最良の予測はクラスVeriscolorになります。一連の比較で左から2番目の葉に到達した場合、モデルの予測は再びVeriscolorになります。これは、トレーニングセットでは、この葉に到達したそのクラスのサンプルが4つあったのに対し、VirginicaクラスとVirginicaのサンプルは1つだけだったためです。 Setosaクラスのゼロサンプル。

決定木は、分類または回帰の問題に使用できます。分類の問題について説明することから始めて、ツリートレーニングアルゴリズムがどのように機能するかを説明しましょう。

練習:

sklearnを使用してツリーをトレーニングする方法を見てから、そのメカニズムについて説明します。

データセットのダウンロード:

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
iris = load_iris()
X = iris['data']
y = iris['target']
names = iris['target_names']
feature_names = iris['feature_names']
# One hot encoding
enc = OneHotEncoder()
Y = enc.fit_transform(y[:, np.newaxis]).toarray()
# Modifying the dataset
X[y==1,2] = X[y==1,2] + 0.3
# Split the data set into training and testing
X_train, X_test, Y_train, Y_test = train_test_split(
    X, Y, test_size=0.5, random_state=2)
# Decreasing the train set to make things more interesting
X_train = X_train[30:,:]
Y_train = Y_train[30:,:]

# Visualize the data sets
import matplotlib
import matplotlib.pyplot as plt
plt.figure(figsize=(16, 6))
plt.subplot(1, 2, 1)
for target, target_name in enumerate(names):
    X_plot = X[y == target]
    plt.plot(X_plot[:, 0], X_plot[:, 1], linestyle='none', marker='o', label=target_name)
plt.xlabel(feature_names[0])
plt.ylabel(feature_names[1])
plt.axis('equal')
plt.legend();
plt.subplot(1, 2, 2)
for target, target_name in enumerate(names):
    X_plot = X[y == target]
    plt.plot(X_plot[:, 2], X_plot[:, 3], linestyle='none', marker='o', label=target_name)
plt.xlabel(feature_names[2])
plt.ylabel(feature_names[3])
plt.axis('equal')
plt.legend();

      
                
Fig.2 Visualization of the modified Iris dataset.

plt.figure(figsize=(16, 6))
plt.subplot(1, 2, 1)
for target, target_name in enumerate(names):
    X_plot = X_train[Y_train[:,target] == 1]
    plt.plot(X_plot[:, 0], X_plot[:, 1], linestyle='none', marker='o', label=target_name)
plt.xlabel(feature_names[0])
plt.ylabel(feature_names[1])
plt.axis('equal')
plt.legend();
plt.subplot(1, 2, 2)
for target, target_name in enumerate(names):
    X_plot = X_train[Y_train[:,target] == 1]
    plt.plot(X_plot[:, 2], X_plot[:, 3], linestyle='none', marker='o', label=target_name)
plt.xlabel(feature_names[2])
plt.ylabel(feature_names[3])
plt.axis('equal')
plt.legend();

      
                
Fig.3 — Just the (reduced) train set.

from sklearn import tree
import graphviz
iristree = tree.DecisionTreeClassifier(max_depth=3, criterion='gini', random_state=0)
iristree.fit(X_train, enc.inverse_transform(Y_train))
feature_names = ['sepal length', 'sepal width', 'petal length', 'petal width']
dot_data = tree.export_graphviz(iristree, out_file=None, 
                      feature_names=feature_names,  
                      class_names=names,
                      filled=True, rounded=True,  
                      special_characters=True)  
graph = graphviz.Source(dot_data)
display(graph)

トレインセットでのこのモデルの分類精度と、それに続くテストセットを見てみましょう。

from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
iristrainpred = iristree.predict(X_train)
iristestpred = iristree.predict(X_test)
# train precision:
display(precision_score(enc.inverse_transform(Y_train), iristrainpred.reshape(-1,1), average='micro', labels=[0]))
display(precision_score(enc.inverse_transform(Y_train), iristrainpred.reshape(-1,1), average='micro', labels=[1]))
display(precision_score(enc.inverse_transform(Y_train), iristrainpred.reshape(-1,1), average='micro', labels=[2]))
>>> 1.0
>>> 0.9047619047619048
>>> 1.0
# test precision:
display(precision_score(enc.inverse_transform(Y_test), iristestpred.reshape(-1,1), average='micro', labels=[0]))
display(precision_score(enc.inverse_transform(Y_test), iristestpred.reshape(-1,1), average='micro', labels=[1]))
display(precision_score(enc.inverse_transform(Y_test), iristestpred.reshape(-1,1), average='micro', labels=[2]))
>>> 1.0
>>> 0.7586206896551724
>>> 0.9473684210526315

そして今、理論に移ります—木はどのように訓練するのですか?

言い換えると、各ノードに配置する最適な機能としきい値をどのように選択するのでしょうか。

ジニ不純物

他の機械学習モデルと同様に、デシジョンツリートレーニングメカニズムは、トレインセットの予測エラーによって引き起こされる損失を最小限に抑えようとします。Gini不純物指数(イタリアの統計家Corrado Giniの後)は、分類精度の自然な尺度です。

図4—樹木の2つの一般的な列車の目的:ジーニとエントロピー。P(ci)は、母集団からクラスciサンプルをランダムに選択する確率です。nはクラスの数です。

高いGiniは不均一な母集団(各クラスからの類似したサンプル量)に対応し、低いGiniは均一な母集団(つまり、主に単一のクラスで構成されている)を示します。

可能な最大のGini値は、クラスの数によって異なります。Cクラスの分類問題では、可能な最大のGiniは1–1 / Cです(クラスが均等に配置されている場合)。最小のGiniは0であり、母集団全体が単一のクラスで構成されている場合に達成されます。

Gini不純物指数は、分類がランダムに行われる場合の分類エラーの確率を測定します。

なんで?

クラスciからサンプルをランダムに選択する確率はp(ci)であるためです。それを選んだら、間違ったクラスを予測する確率は(1-p(ci))です。すべてのクラスでp(ci)*(1-p(ci))を合計すると、図4のGini不純物の式が得られます。

ジニ係数を目的として、ツリーは各ステップで、結果として得られる2つの母集団の加重平均ジニを最大に減少させる(または加重平均の均一性を最大に増加させる)方法で母集団を分割する機能としきい値を選択します。言い換えると、トレインロジックは、結果として得られる2つの母集団でランダムな分類エラーが発生する可能性を最小限に抑え、サブ母集団の大きい方に重点を置きます。

そしてそうです—メカニズムはすべてのサンプル値を調べ、基準に従ってそれらを分割して、結果のGiniをチェックします。

この定義から、しきい値が常に少なくとも1つの列車サンプルで見つかった実際の値である理由も理解できます。結果の分割は同じになるため、サンプル間のギャップにある値を使用してもメリットはありません。

ツリートレーニングに一般的に使用されるもう1つのメトリックは、エントロピーです(図4の式を参照)。

エントロピ

Gini戦略は次のステップでランダム分類エラーを最小化することを目的としていますが、エントロピー最小化戦略は情報ゲインを最大化することを目的としています。

情報獲得

母集団が10のクラスにどのように分割されるかについての事前の知識がない場合、それらの間で均等に分割されると想定します。この場合、サンプルの分類を見つけるために、平均3.3のはい/いいえの質問が必要です(クラス1〜5ですか?そうでない場合は、クラス6〜10など)。これは、母集団のエントロピーが3.3ビットであることを意味します。

しかし、人口分布に関する情報を提供する何か(巧妙な分割など)を行ったと仮定しましょう。サンプルの50%がクラス1にあり、25%がクラス2にあり、サンプルの25%がクラス3。この場合、母集団のエントロピーは1.5になります。ランダムなサンプルを記述するために必要なのは1.5ビットだけです。(最初の質問—あなたはクラス1ですか?シーケンスは50%の確率でここで終了します。2番目の質問—あなたはクラス2ですか?これ以上の質問は必要ありません—したがって、平均で50%* 1 + 50%* 2=1.5の質問です。 )。私たちが得たその情報は1.8ビットの価値があります。

Giniと同様に、エントロピーを最小化することは、より均質な母集団を作成することと一致します。これは、均質な母集団のエントロピーが低いためです(単一クラスの母集団の極端な場合、エントロピーは0です。yes/ noの質問をする必要はありません)。

ジニまたはエントロピー?

ほとんどの情報源は、2つの戦略の違いはそれほど重要ではないと主張しています(実際、先ほど取り組んだ問題についてエントロピーツリーをトレーニングしようとすると、まったく同じ分割が得られます)。理由は簡単にわかります。Giniがクラス確率の期待値を最大化するのに対し、エントロピーはログクラス確率の期待値を最大化します。ただし、対数確率は確率の単調増加関数であるため、通常はまったく同じように動作します。ただし、人口が非常に不均衡な場合、エントロピーの最小化はGiniとは異なる構成を選択する可能性があります。たとえば、ROSEのHacideデータセットでは(ランダムなオーバーサンプリングの例、Lunadron et al。2021)1000のトレーニングサンプルがあります— 980はクラス0に属し、20はクラス1に属します。ツリーが例aまたは例bのいずれかに従ってそれを分割するしきい値を選択できるとしましょ図5で。どちらの例でも、主に多数派クラスで構成される人口の多いノードと、主に少数派クラスで構成される人口の少ない2番目のノードが作成されることに注意してください。

このような場合、小さい値での対数関数の急峻さは、エントロピー基準を動機付けて、Gini基準よりも強力に、人口の多いノードを浄化します。したがって、数学を計算すると、Gini基準はsplit aを選択し、エントロピー基準はsplitbを選択することがわかります

これにより、機能/しきい値の選択が異なる場合があります。必ずしも良いか悪いかではありません—これは私たちの目標に依存します。

図5高度に不均衡なデータの2つの可能な分割(Hacideデータセット、ROSEからの例)。

最初にバランスの取れた母集団に問題がある場合でも、分類ツリーの下位ノードには通常、非常に不均衡な母集団があることに注意してください。

トレーニングの終了

ツリー内のパスが指定された深度値に達するか、Gini /エントロピーの母集団がゼロになると、トレーニングを停止します。すべてのパスがトレーニングを停止すると、ツリーの準備が整います。

一般的な方法は、木の深さを制限することです。もう1つは、リーフ内のサンプル数を制限することです(しきい値より少ないサンプルを許可しない)。両方の方法は、列車セットの過剰適合を防ぐために行われます。

回帰ツリー

分類ツリーのトレーニングの詳細を理解したので、回帰ツリーを理解するのは非常に簡単です。回帰問題のラベルは、離散的ではなく連続的です(たとえば、特定の薬剤投与量の有効性、%で測定)ケース)。このタイプの問題に関するトレーニングでは、回帰ツリーも分類されますが、ラベルは各ノードのサンプルの平均値として動的に計算されます。ここでは、最小化の目的として、Giniとエントロピーの代わりに、平均二乗誤差またはカイ二乗尺度を使用するのが一般的です。

© Copyright 2021 - 2023 | hachiwiki.com | All Rights Reserved