[Conceptos básicos del aprendizaje automático] Algoritmo de clasificación de árboles de decisión

Algoritmo de clasificación de árboles de decisión

La esencia de un árbol de decisión es un árbol, cada uno de sus nodos hoja representa una determinada clasificación. Al seleccionar las ramas de todo el árbol y finalmente llegar al nodo de la hoja, puede obtener qué tipo de clasificación es.


1. Cómo elegir la mejor decisión

1. Principio de la navaja de Occam

"Si no es necesario, no aumente su valor". Es decir, a la hora de tomar una decisión, tenemos que elegir el camino que nos permita obtener el resultado más rápido. Para decirlo más sin rodeos es "Puedes usar tres puntos, no muevas cinco para tener éxito".

2. Entropía de la información

Para aplicar el principio de navaja de Occam a los árboles de decisión, necesitamos introducir la entropía de información. No daré más detalles sobre la entropía de la información aquí. Solo necesito entender que la entropía de la información representa un estado de confusión de la información. Cuanto más ordenado sea un conjunto de datos, menor será la entropía de la información, por lo que para obtener el estado de la entropía de información más pequeña, puede elegir la dirección con el mayor cambio en la entropía de la información.
Método de cálculo de la entropía de la información:
X = {x1, x2… xn} representa un conjunto de variables y P (xi) representa la probabilidad correspondiente.
Fórmula de cálculo de entropía de información

Si hay muchas características para un conjunto de datos, entonces hay entropía de información condicional para cada característica . Entonces, la fórmula de cálculo de la entropía condicional es:
T = {t1, t2,… tm} representa la característica T, y la probabilidad de su aparición en la muestra para diferentes características ti es | s | / S La fórmula de cálculo del
Fórmula de cálculo de entropía condicional
incremento de entropía de información es la siguiente:
esa es la base Entropía de información menos entropía condicional.
Incremento de entropía de información

3. Construcción del árbol de decisiones

A través de todos los incrementos de entropía de información en el conjunto de datos, se selecciona la característica del incremento de entropía de información más grande. El conjunto de datos completo está dividido por esta característica. Obtenga un conjunto de datos más pequeño y continúe dividiendo en este conjunto de datos hasta que se encuentre el valor predicho final. (Esto puede ser un poco abstracto, consulte los ejemplos y códigos a continuación)

2. Ejemplos

Los datos se seleccionan de un conjunto de datos bancarios en kaggle . El propósito es predecir si el cliente realizará el depósito esperado. El conjunto de datos se puede descargar en el enlace anterior. El siguiente es un ejemplo de datos. El depósito final es el valor a predecir.

años trabajo marital educación defecto equilibrar alojamiento préstamo contacto día mes duración Campaña días anterior poutcome depositar
0 59 administración. casado secundario No 2343 si No desconocido 5 mayo 1042 1 -1 0 desconocido si
1 56 administración. casado secundario No 45 No No desconocido 5 mayo 1467 1 -1 0 desconocido si
2 41 técnico casado secundario No 1270 si No desconocido 5 mayo 1389 1 -1 0 desconocido si
3 55 servicios casado secundario No 2476 si No desconocido 5 mayo 579 1 -1 0 desconocido si
4 54 administración. casado terciario No 184 No No desconocido 5 mayo 673 2 -1 0 desconocido si

Las estadísticas de este conjunto de datos pueden obtener variables características y sus valores (divididos en dos tipos).
1. El valor característico es una cadena
[1] trabajo : administrador, técnico, servicios, gerencia, jubilado, obrero, desempleado, empresario, empleada doméstica, desconocido, autónomo, estudiante
[2] marital : casado, soltero, divorciado
[3] educación : secundaria, terciaria, primaria, desconocida
[4] incumplimiento : sí, no
[5] vivienda : sí, no
[6] préstamo : sí, no
[7] depósito : sí, no (variable dependiente)
[8 ] contacto : desconocido, celular, teléfono
[9] mes: ene, feb, mar, abr, may, jun, jul, ago, sep, oct, nov, dic
[10] poutcome : desconocido, otro, fracaso, éxito
2. El valor característico es un número
[1] edad
[2] saldo
[3] día
[4] duración
[5] campaña
[6] pdías
[7] anterior
En este conjunto de datos, necesitamos seleccionar una función para dividir el conjunto de datos. ¿Cómo elegir características para la división? La respuesta es elegir la característica con el mayor aumento de entropía de información. El incremento de entropía máximo para la primera división de este conjunto de datos es el equilibrio (calculado). A través del valor del saldo, se puede dividir en varias categorías, se puede calcular el incremento de entropía de la información bajo la división de varias categorías y el conjunto de datos se puede dividir continuamente hasta obtener el resultado final.
[ Explicación ] Debido a que algunas características de este conjunto de datos son valores numéricos, la división es demasiado fina al tomar una decisión, por lo que no se puede obtener un mejor resultado, por lo que los datos se pueden discretizar y los datos dentro de un rango se pueden considerar como Es una especie de dato. La discretización no se hace en este artículo.

Dos, implementación de código

# 决策树预测

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

para resumir

referencias

  1. Libros prácticos de aprendizaje automático
  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

Supongo que te gusta

Origin blog.csdn.net/qq_37753409/article/details/108884162
Recomendado
Clasificación