【機械学習の基礎】意思決定ツリー分類アルゴリズム

デシジョンツリー分類アルゴリズム

決定ツリーの本質はツリーであり、そのリーフノードのそれぞれが特定の分類を表します。ツリー全体のブランチを選択し、最終的にリーフノードに到達することで、それがどのような分類であるかを取得できます。


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])

総括する

参照

  1. 機械学習の実践的な本
  2. https://www.kaggle.com/shirantha/bank-marketing-data-a-decision-tree-approach/data
  3. https://github.com/apachecn/AiLearning/blob/master/docs/ml/3.%E5%86%B3%E7%AD%96%E6%A0%91.md
  4. https://blog.csdn.net/colourful_sky/article/details/82056125
  5. https://www.cnblogs.com/starfire86/p/5749328.html

おすすめ

転載: blog.csdn.net/qq_37753409/article/details/108884162
おすすめ