デシジョンツリー分類アルゴリズム
決定ツリーの本質はツリーであり、そのリーフノードのそれぞれが特定の分類を表します。ツリー全体のブランチを選択し、最終的にリーフノードに到達することで、それがどのような分類であるかを取得できます。
記事ディレクトリ
1.最良の決定を選択する方法
1.オッカムのかみそりの原理
「必要がなければ、その価値を上げないでください。」つまり、決定を下すときは、最速の結果を得ることができる方法を選択する必要があります。もっと率直に言うと、「3つのポイントを使用できます。成功するために5つ動かさないでください」です。
2.情報エントロピー
Occamのかみそりの原理を意思決定ツリーに適用するには、情報エントロピーを導入する必要があります。ここでは、情報エントロピーについては詳しく説明しません。情報エントロピーは情報の混乱状態を表すことを理解する必要があります。データセットが整然としているほど、情報エントロピーは小さくなります。したがって、最小の情報エントロピーの状態を取得するには、情報エントロピーの変化が最も大きい方向を選択できます。
情報エントロピーの計算方法:
X = {x1、x2…xn}は変数のセットを表し、P(xi)は対応する確率を表します。
データのセットに多くの機能がある場合、各機能には条件付き情報エントロピーがあります。条件付きエントロピーの計算式は次のとおりです
。T= {t1、t2、…tm}は特徴Tを表し、さまざまな特徴tiのサンプルに彼が現れる確率は| s | / Sです。
情報エントロピー増分の計算式は次のとおりです。
これが基礎です。情報エントロピーから条件付きエントロピーを引いたもの。
3.意思決定ツリーの構築
データセットのすべての情報エントロピー増分を通じて、最大の情報エントロピー増分の機能が選択されます。データセット全体がこの機能によって分割されます。より小さなデータセットを取得し、最終的な予測値が見つかるまで、このデータセットで分割を続けます。(これは少し抽象的なかもしれません。以下の例とコードを参照してください)
2.例
データは、kaggleの銀行データセットから選択されます。目的は、顧客が予想される預金を行うかどうかを予測することです。データセットは上記のリンクからダウンロードできます。以下はデータの例です。最終預金は予測される価値です。
年齢 | ジョブ | 婚姻 | 教育 | デフォルト | 残高 | ハウジング | ローン | 連絡先 | 日 | 月 | デュレーション | 運動 | pdays | 前 | poutcome | 預り金 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 59 | 管理者。 | 既婚 | 二次 | 番号 | 2343 | はい | 番号 | わからない | 5 | 五月 | 1042 | 1 | -1 | 0 | わからない | はい |
1 | 56 | 管理者。 | 既婚 | 二次 | 番号 | 45 | 番号 | 番号 | わからない | 5 | 五月 | 1467 | 1 | -1 | 0 | わからない | はい |
2 | 41 | 技術者 | 既婚 | 二次 | 番号 | 1270 | はい | 番号 | わからない | 5 | 五月 | 1389 | 1 | -1 | 0 | わからない | はい |
3 | 55 | サービス | 既婚 | 二次 | 番号 | 2476 | はい | 番号 | わからない | 5 | 五月 | 579 | 1 | -1 | 0 | わからない | はい |
4 | 54 | 管理者。 | 既婚 | 三次 | 番号 | 184 | 番号 | 番号 | わからない | 5 | 五月 | 673 | 2 | -1 | 0 | わからない | はい |
このデータセットの統計は、特性変数とその値を取得できます(2つのタイプに分けられます)。
1.特徴的な値は文字列です
[1]仕事:管理者、技術者、サービス、管理、退職、ブルーカラー、失業者、起業家、女中、不明、自営業、学生
[2]夫婦:既婚、独身、離婚
[3]教育:二次、三次、一次、不明
[4]デフォルト:はい、いいえ
[5]住宅:はい、いいえ
[6]ローン:はい、いいえ
[7]預金:はい、いいえ(従属変数)
[8 ]連絡先:不明、携帯電話、電話
[9]月:jan、feb、mar、apr、may、jun、jul、aug、sep、oct、nov、dec
[10]結果:不明、その他、失敗、成功
2。特性値は数値
[1]年齢
[2]です。バランス
[3]日
[4]期間
[5]キャンペーン
[6] pdays
[7]前
このデータセットでは、データセットを分割する機能を選択する必要があります。分割する機能を選択する方法は?答えは、情報エントロピーが最も増加する機能を選択することです。このデータセットの最初の分割の最大エントロピー増分は、バランス(計算)です。バランスの値を通じて、いくつかのカテゴリに分割でき、いくつかのカテゴリの分割の下での情報エントロピーの増分を計算でき、最終結果が得られるまでデータセットを継続的に分割できます。
【解説】本データセットの特徴の一部が数値であるため、分割が細かく決定しすぎて、より良い結果が得られず、離散化でき、範囲内のデータとみなすことができます。一種のデータです。この記事では、離散化は行われません。
2、コードの実装
# 决策树预测
import numpy as np
import pandas as pd
import math
class BankPredict():
def __init__(self):
pass
# 读取数据
def import_data(self, filename):
input_csvdata = pd.read_csv(filename)
feature_name = np.array(input_csvdata.columns.values).tolist()
input_data_set = np.array(input_csvdata).tolist()
# print(feature_name)
# print(input_data_set)
return input_data_set, feature_name
# 划分数据集 (通过某个特征的取值进行划分)
def split_data(self, data_set, axis, class_value):
ret_data_set = []
for feat_vector in data_set:
if feat_vector[axis] == class_value: # 获取到相同的取值,然后进行划分,返回相同分类的列表
reduce_feat_vector = feat_vector[0:axis]
reduce_feat_vector.extend(feat_vector[axis+1:])
ret_data_set.append(reduce_feat_vector)
# print (ret_data_set)
return ret_data_set
# 计算某个特定特征的信息熵
def cal_shannon_evt(self, sub_data_set):
# 计算指定列(特征)的某一种类别信息熵 对于本问题来说,结果只会有YES/NO sub_data_set里面只存储最后一列的信息 大小为n*1
class_count = {
}
for item in sub_data_set:
class_count[item[-1]] = class_count.get(item[-1], 0) + 1
# print(class_count)
# 计算此特征本种分类下的信息熵
shannon_evt = 0.0
data_size = len(sub_data_set)
for class_item in class_count:
pxi = (float(class_count[class_item])/float(data_size))
shannon_evt = shannon_evt - pxi*math.log2(pxi)
return shannon_evt
# 计算条件熵
def cal_condition_evt(self, data_set, axis, class_value):
# 计算在某个特征的划分下,划分之后的条件熵(用信息熵*特定特征分类的出现的概率) axis可表示特征 class_value可表示特征内的分类情况
condition_evt = 0.0
data_size = len(data_set)
for value in class_value:
sub_data_set = self.split_data(data_set, axis, value)
sub_shannon_evt = self.cal_shannon_evt(sub_data_set)
# 计算条件熵
condition_evt = condition_evt + (float(len(sub_data_set))/data_size)*sub_shannon_evt
return condition_evt
# 计算熵增量
def inc_evt(self, data_set, base_evt, axis):
# 获取某一列
feature_list = [item[axis] for item in data_set]
# print(feature_list)
class_value = set(feature_list)
new_evt = self.cal_condition_evt(data_set, axis, class_value)
# 计算熵增 信息熵-条件熵
ie = base_evt - new_evt
return ie
# 选择熵增最大的特征进行划分
def choose_best_feature(self, data_set):
feature_num = len(data_set[0]) - 1 # 排除最后一列
base_evt = self.cal_shannon_evt(data_set)
best_evt = 0.0
best_feature = -1
for axis in range(feature_num):
axis_feature_evt = self.inc_evt(data_set, base_evt, axis)
if axis_feature_evt > best_evt:
best_evt = axis_feature_evt
best_feature = axis
# 返回熵增最大的特征行
return best_feature
# 当只有决策到只有一个类别时,输出出现次数最多的类别
def majority_class(self, class_list):
class_count = {
}
for item in class_list:
class_count[item] = class_list[item]
temp_num = 0
result_class = ""
for item in class_count:
if temp_num < class_count[item]:
temp_num = class_count[item]
result_class = item
return result_class
# 构建决策树
def create_decision_tree(self, data_set, label):
# 总分类列表,本题中只有YES/NO
class_list = [example[-1] for example in data_set]
'''
决策成功的两种情况
1. 本次划分之后分类列表中只有一种分类,直接结束。
2. 本次划分使用完了所有特征还是不能划分成一个分类,选择出现次数最多的分类结束。
'''
# 情况1
if class_list.count(class_list[0]) == len(class_list):
return class_list[0]
# 情况2
if len(data_set[0]) == 1:
return self.majority_class(class_list)
best_feature = self.choose_best_feature(data_set)
best_feature_label = label[best_feature]
my_tree = {
best_feature_label:{
}} # 对于某个特征的树
# 已经使用过的特征进行删除标记
del(label[best_feature]) #这里删除只会删掉引用
feature_value = [example[best_feature] for example in data_set]
values = set(feature_value)
# print(best_feature_label, values)
# 对于每一种划分的不同类别都进行建树
for value in values:
sub_label = label[:]
# print(best_feature, value)
my_tree[best_feature_label][value] = self.create_decision_tree(self.split_data(data_set, best_feature, value), sub_label)
return my_tree
# 测试单个节点
def single_test(self, my_tree, testcase, labels):
# 获取根节点
root_key = list(my_tree.keys())[0]
# 根节点下的所有子树
all_child_tree = my_tree[root_key]
# 和测试节点进行比较
feature_index = labels.index(root_key)
testcase_key = testcase[feature_index]
# print('-------------------')
# print(labels)
# print('root_key: ', root_key, '/all_child_tree: ', all_child_tree, '/feature_index: ', feature_index, '/testcase_key: ', testcase_key)
# 获取测试节点对应子树
child_tree = all_child_tree[testcase_key]
# print('root_key: ', root_key, '/all_child_tree: ', all_child_tree, '/testcase_key: ', testcase_key, '/child_tree: ', child_tree)
if isinstance(child_tree, dict):
result = self.single_test(child_tree, testcase, labels)
else:
result = child_tree
return result
_DEBUG = True
if __name__ == "__main__":
FILE_NAME = r'2020\ML\ML_action\\2.DecisionTree\data\bank.csv'
bp = BankPredict()
print("data loading...")
train_size = 11000
import_data_set, feature_name = bp.import_data(FILE_NAME)
label = feature_name.copy()
data_set = import_data_set[0:train_size]
print("data load over.")
print('building tree...')
my_tree = bp.create_decision_tree(data_set, label)
print('build tree end.')
if _DEBUG == True:
# 测试
print("test result = ", bp.single_test(my_tree, data_set[2], feature_name))
print("real result = ", data_set[2][-1])
総括する
参照
- 機械学習の実践的な本
- https://www.kaggle.com/shirantha/bank-marketing-data-a-decision-tree-approach/data
- https://github.com/apachecn/AiLearning/blob/master/docs/ml/3.%E5%86%B3%E7%AD%96%E6%A0%91.md
- https://blog.csdn.net/colourful_sky/article/details/82056125
- https://www.cnblogs.com/starfire86/p/5749328.html