決定木-C 4.5
31999 ワード
C4.5アルゴリズムはQuinlanによって1993年に提案され、コア部分はID 3アルゴリズムと似ており、ID 3アルゴリズムに基づいて改造されただけである--特徴選択過程で情報利得比を選択基準としている.
【具体的な方法】:ルートノード(root node)から出発し、ノードに対してすべての可能な特徴の情報利得比を計算し、情報利得比が最大の特徴をノードの特徴として選択し、この特徴の異なる値からサブノードを確立する. はさらにサブノードに対して以上の方法を再帰的に呼び出し、決定ツリーを構築する.すべてのフィーチャーの情報利得が小さいか、フィーチャーが選択できないまで. は最後に決定ツリーを得た.
【アルゴリズム】:C 4.5アルゴリズムを生成します.入力:トレーニングデータセットD、フィーチャーセットA、しきい値e. 出力:決定ツリーT. プロセス: Dのすべてのインスタンスが同じクラスC k Cに属している場合k Ck、Tを単一ノードツリーとし、C k C_k Ckはこのノードのクラスとして、Tを返す. A=∅A=emptyset A=∅の場合、Tを単一ノードツリーとし、Dのインスタンス数が最も大きいクラスC k C_k Ckはこのノードのクラスとして、Tを返す. それ以外の場合、情報ゲイン比式に従ってAにおける各特徴対Dの情報ゲイン比を算出し、情報ゲイン比が最大となる特徴A g A_を選択するg Ag; A g A_g Agの情報利得比が閾値eより小さい場合、Tを単一ノードツリーとし、D中のインスタンス数が最大のクラスC k C_k Ckはこのノードのクラスとして、Tを返す. そうでなければ、A g A_g Agの各可能値a i a_i ai,依A g=a i A_g = a_i Ag=ai Dをいくつかの非空子セットD i D_に分割するi Di,D i D_i Diの中で実例数が最も大きいクラスをタグとして、サブノードを構築し、ノードとそのサブノードからツリーTを構成し、Tを返す. 対のノードi、D i D_i Diはトレーニングセットであり、A−A g A−{A_g}A−Agを特徴セットとし、(1)~(5)ステップを再帰的に呼び出し、サブツリーT i T_を得るi Ti,T i T_を返すi Ti.
情報エントロピー、情報ゲイン、および情報ゲイン比については、ブログモデル選択-決定ツリーを参照してください.
【情報エントロピー計算式】E n t(D)=Σi=i k−∣Y i∣Y∣l o g 2∣Y i∣Y∣Ent(D)=sum_{i=i}^{k}-\frac{|Y_i|}{|Y|}log_2frac{|Y_i|}{|Y|}Ent(D)=i=iΣk−∣Y∣Yi∣log 2∣Y∣Yi∣のうち、|Y|は現在のデータセットDのラベル数、kはデータセットDのラベル種類数を表す.例えば、現在5つのサンプルがあり、各サンプルの分類は1、0、1、2、0であり、|Y|=5、k=3である.∣ Y i ∣ |Y_i|∣Yi∣は、指定されたラベル種別のラベル数、例えばY 0 Y_を示す0 Y 0がラベル種別0に対応すると、∣Y 0∣=2|Y_0|=2∣Y 0∣=2,同理可得∣Y 1∣=2,∣Y 2∣=1|Y_1| = 2, |Y_2|= 1 ∣Y1∣=2,∣Y2∣=1.
【情報利得計算式】:G a i n(D,a)=Σi=1∣a∣D i∣D∣E n t(D i)Gain(D,a)=sum_{i=1}^{|a|}frac{|D_i|}{|D|}Ent(D_i)Gain(D,a)=1ΣaD i D_i Diは、指定された特徴値に基づいて分割されたデータセット、∣D i∣|D_を表すi|∣Di∣は、そのデータセットのサンプル数を示す.
【情報利得比計算式】:I V(a)=Σi=1∣a∣−∣D i∣D∣l o g 2∣D i∣D∣G a i n r a t i o(D,a)=G a i n(D,a)I V(a)IV(a)=sum_{i=1}^{|a|}-\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|}\\Gain_{ratio}(D, a) =\frac{Gain(D, a)}{IV(a)} IV(a)=i=1∑∣a∣−∣D∣∣Di∣log2∣D∣∣Di∣Gainratio(D,a)=IV(a)Gain(D,a)
コード実装
C4.5アルゴリズムはID 3アルゴリズムと同じで、離散型データ及び分類タスクの処理にしか使用できないので、sklearnを選択する.Datasetsのirisアヤメデータセット.
決定ツリーのノード構造コード:
calc_shannon_ent()
calc_shannon_ent情報利得計算関数で、2つのパラメータdataとlabelsを受け入れる. data:データセット labels:ラベルセット まず,データセットの個数と特徴数,および分類の個数を取得する.
注意:labels_count/data_countの結果は,元のデータセットの各分類の確率である.
次に、元のデータセットの情報エントロピーを算出し、区分を格納した各特徴情報ゲイン比情報のリストgain_を作成するlist.
そして、各特徴区分されたデータセットの情報エントロピー及びその特徴対応IVを計算する.
最後に、情報利得比が最も大きいフィーチャーの下付きスケールを返します.
【完全コード】:
split_dataset()
split_Dataset()メソッドは、4つのパラメータを受け入れるフィーチャー値とフィーチャー値に基づいてデータセットを分割します. data:データセット labels:ラベルリスト feature:フィーチャー value:フィーチャー値 split_Dataset()は、分割されたデータセットとラベルセットを含むメタグループを返します.
【完全コード】:
voting_label()
voting_Label()投票関数は,葉結点の分類結果を決定するために用いられる.このメソッドは、1つのパラメータlabels、ラベルセットのみを受け入れます.
【完全コード】:
create_tree()
create_tree()は、3つのパラメータを受け入れる決定ツリー関数を再帰的に作成します. data:データ labels:ラベルセット features:フィーチャーセット まず,特徴セットが存在するか否かを判断し,存在しなければ現在のノードをリーフノードとする.
そして,ラベルセットを判断し,1つのラベルのみであれば現在のノードをリーフノードとする.
次に、calc_を呼び出すshannon_ent()メソッドは,最適特徴の下付き文字を取得し,下付き文字に基づいて最適特徴を得る.
ステップ4では、ノードを作成し、分割されたフィーチャーをフィーチャーセットから削除します.
第5のステップでは、最適な特徴に基づいてデータセットを分割します.
注意:best_feature_infoは、各特徴値に対応するデータセットを含む辞書です.
ステップ6では、各特徴値に対応するデータセットに基づいてcreate_を再帰的に呼び出すtree()メソッドを使用して、サブノードを作成します.
最後に、ルートノードを返します.
【完全コード】:
【create_tree()関数の呼び出し】
ID 3アルゴリズムの出力結果を比較すると,ルートノードの特徴が変化することが分かった.すなわち,異なる特徴選択基準に基づいて,決定ツリー内部ノードの特徴もそれに応じて変化する.
完全なコードおよび呼び出しプロセスは、転送ゲートから取得できます.
リファレンス《統計学習方法》李航 『機械学習』周志華
【具体的な方法】:
【アルゴリズム】:C 4.5アルゴリズムを生成します.
情報エントロピー、情報ゲイン、および情報ゲイン比については、ブログモデル選択-決定ツリーを参照してください.
【情報エントロピー計算式】E n t(D)=Σi=i k−∣Y i∣Y∣l o g 2∣Y i∣Y∣Ent(D)=sum_{i=i}^{k}-\frac{|Y_i|}{|Y|}log_2frac{|Y_i|}{|Y|}Ent(D)=i=iΣk−∣Y∣Yi∣log 2∣Y∣Yi∣のうち、|Y|は現在のデータセットDのラベル数、kはデータセットDのラベル種類数を表す.例えば、現在5つのサンプルがあり、各サンプルの分類は1、0、1、2、0であり、|Y|=5、k=3である.∣ Y i ∣ |Y_i|∣Yi∣は、指定されたラベル種別のラベル数、例えばY 0 Y_を示す0 Y 0がラベル種別0に対応すると、∣Y 0∣=2|Y_0|=2∣Y 0∣=2,同理可得∣Y 1∣=2,∣Y 2∣=1|Y_1| = 2, |Y_2|= 1 ∣Y1∣=2,∣Y2∣=1.
【情報利得計算式】:G a i n(D,a)=Σi=1∣a∣D i∣D∣E n t(D i)Gain(D,a)=sum_{i=1}^{|a|}frac{|D_i|}{|D|}Ent(D_i)Gain(D,a)=1ΣaD i D_i Diは、指定された特徴値に基づいて分割されたデータセット、∣D i∣|D_を表すi|∣Di∣は、そのデータセットのサンプル数を示す.
【情報利得比計算式】:I V(a)=Σi=1∣a∣−∣D i∣D∣l o g 2∣D i∣D∣G a i n r a t i o(D,a)=G a i n(D,a)I V(a)IV(a)=sum_{i=1}^{|a|}-\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|}\\Gain_{ratio}(D, a) =\frac{Gain(D, a)}{IV(a)} IV(a)=i=1∑∣a∣−∣D∣∣Di∣log2∣D∣∣Di∣Gainratio(D,a)=IV(a)Gain(D,a)
コード実装
C4.5アルゴリズムはID 3アルゴリズムと同じで、離散型データ及び分類タスクの処理にしか使用できないので、sklearnを選択する.Datasetsのirisアヤメデータセット.
import numpy as np
from sklearn.datasets import load_iris
dataset = load_iris()
x = dataset.data
y = dataset.target
features = dataset.feature_names
決定ツリーのノード構造コード:
class Node:
def __init__(self, value, type='decision'):
self.value = value
self.type = type
self.children = {}
calc_shannon_ent()
calc_shannon_ent情報利得計算関数で、2つのパラメータdataとlabelsを受け入れる.
data_count = float(data.shape[0])
features = data.shape[1]
labels_count = np.array([labels[labels == label].size for label in set(labels)])
注意:labels_count/data_countの結果は,元のデータセットの各分類の確率である.
次に、元のデータセットの情報エントロピーを算出し、区分を格納した各特徴情報ゲイン比情報のリストgain_を作成するlist.
base_ent = -np.sum((labels_count / data_count) * np.log2(labels_count / data_count))
gain_list = []
そして、各特徴区分されたデータセットの情報エントロピー及びその特徴対応IVを計算する.
for feature in range(0, features):
#
feature_data = data[:, feature]
# , key, value
feature_info = {feature: feature_data[feature_data == feature].size for feature in set(feature_data)}
feature_shannonEnt, IV = 0, 0
#
for feature_value in feature_info:
#
feature_count = float(feature_info[feature_value])
label_data = labels[feature_data == feature_value]
labels_feature = np.array([label_data[label_data == label].size for label in set(label_data)])
#
p_label = labels_feature / feature_count
feature_shannonEnt += (feature_count / data_count) * np.sum(-p_label * np.log2(p_label))
# IV
IV += (feature_count / data_count) * np.log2(feature_count / data_count)
# gain_list
gain_list.append((base_ent - feature_shannonEnt) / IV)
最後に、情報利得比が最も大きいフィーチャーの下付きスケールを返します.
gain_list = np.array(gain_list)
return np.argmax(gain_list)
【完全コード】:
def calc_shannon_ent(data, labels):
data_count = float(data.shape[0])
features = data.shape[1]
#
labels_count = np.array([labels[labels == label].size for label in set(labels)])
#
base_ent = -np.sum((labels_count / data_count) * np.log2(labels_count / data_count))
#
gain_list = []
#
for feature in range(0, features):
#
feature_data = data[:, feature]
# , key, value
feature_info = {feature: feature_data[feature_data == feature].size for feature in set(feature_data)}
feature_shannonEnt, IV = 0, 0
#
for feature_value in feature_info:
#
feature_count = float(feature_info[feature_value])
label_data = labels[feature_data == feature_value]
labels_feature = np.array([label_data[label_data == label].size for label in set(label_data)])
#
p_label = labels_feature / feature_count
feature_shannonEnt += (feature_count / data_count) * np.sum(-p_label * np.log2(p_label))
# IV
IV += (feature_count / data_count) * np.log2(feature_count / data_count)
# gain_list
gain_list.append((base_ent - feature_shannonEnt) / IV)
gain_list = np.array(gain_list)
return np.argmax(gain_list)
split_dataset()
split_Dataset()メソッドは、4つのパラメータを受け入れるフィーチャー値とフィーチャー値に基づいてデータセットを分割します.
【完全コード】:
def split_dataset(data, labels, feature, value):
"""
:param data: ndarray
:param labels: ndarray
:param feature:
:param value:
:return:
"""
feature_data = data[:, feature]
select_rows = feature_data == value
return (np.delete(data[select_rows], feature, axis=1), labels[select_rows])
voting_label()
voting_Label()投票関数は,葉結点の分類結果を決定するために用いられる.このメソッドは、1つのパラメータlabels、ラベルセットのみを受け入れます.
【完全コード】:
def voting_label(labels):
return sorted([(label, len(labels[label == label])) for label in set(labels)])[-1][1]
create_tree()
create_tree()は、3つのパラメータを受け入れる決定ツリー関数を再帰的に作成します.
if len(features) == 0:
return Node(voting_label(labels))
そして,ラベルセットを判断し,1つのラベルのみであれば現在のノードをリーフノードとする.
if len(set(labels)) == 1:
return Node(labels[0])
次に、calc_を呼び出すshannon_ent()メソッドは,最適特徴の下付き文字を取得し,下付き文字に基づいて最適特徴を得る.
best_feature_index = calc_shannon_ent(data, labels)
best_feature = features[best_feature_index]
ステップ4では、ノードを作成し、分割されたフィーチャーをフィーチャーセットから削除します.
node = Node(best_feature)
features = np.delete(features, best_feature_index)
第5のステップでは、最適な特徴に基づいてデータセットを分割します.
best_feature_data = data[:, best_feature_index]
best_feature_info = {feature: best_feature_data[best_feature_data == feature].size for feature in set(best_feature_data)}
注意:best_feature_infoは、各特徴値に対応するデータセットを含む辞書です.
ステップ6では、各特徴値に対応するデータセットに基づいてcreate_を再帰的に呼び出すtree()メソッドを使用して、サブノードを作成します.
for feature_value in best_feature_info:
split_data, split_labels = split_dataset(data, labels, best_feature_index, feature_value)
node.children[feature_value] = create_tree(split_data, split_labels, features)
最後に、ルートノードを返します.
return node
【完全コード】:
def create_tree(data, labels, features):
# : , ,
if len(features) == 0:
return Node(voting_label(labels))
# : , ,
if len(set(labels)) == 1:
return Node(labels[0])
#
best_feature_index = calc_shannon_ent(data, labels)
best_feature = features[best_feature_index]
#
node = Node(best_feature)
#
features = np.delete(features, best_feature_index)
#
best_feature_data = data[:, best_feature_index]
best_feature_info = {feature: best_feature_data[best_feature_data == feature].size for feature in set(best_feature_data)}
for feature_value in best_feature_info:
split_data, split_labels = split_dataset(data, labels, best_feature_index, feature_value)
node.children[feature_value] = create_tree(split_data, split_labels, features)
return node
【create_tree()関数の呼び出し】
root = create_tree(x, y, list(range(x.shape[1])))
print(root.value) # 1
ID 3アルゴリズムの出力結果を比較すると,ルートノードの特徴が変化することが分かった.すなわち,異なる特徴選択基準に基づいて,決定ツリー内部ノードの特徴もそれに応じて変化する.
完全なコードおよび呼び出しプロセスは、転送ゲートから取得できます.
リファレンス