【educoder 机器学习】决策树

决策树说通俗点就是一棵能够替我们做决策的树,或者说是我们人类在要做决策时脑回路的一种表现形式。

本实训项目的主要内容是基于 python 语言搭建出决策树模型对数据分类,并使用 sklearn 的决策时模型对鸢尾花数据进行分类。

第1关:什么是决策树

1.A B
2.B

第2关:信息熵与信息增益

import numpy as np


def calcInfoGain(feature, label, index):
    '''
    计算信息增益
    :param feature:测试用例中字典里的feature,类型为ndarray
    :param label:测试用例中字典里的label,类型为ndarray
    :param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。
    :return:信息增益,类型float
    '''
    # 计算熵
    def calcInfoEntropy(feature, label):
        '''
        计算信息熵
        :param feature:数据集中的特征,类型为ndarray
        :param label:数据集中的标签,类型为ndarray
        :return:信息熵,类型float
        '''
        label_set = set(label)#创建一个无序不重复的元素集
        result = 0
        #统计不同标签各自的数量(一般为0和1)
        for l in label_set:
            count = 0
            for j in range(len(label)):
                if label[j] == l:
                    count += 1
            # 计算标签在数据集中出现的概率
            p = count / len(label)
            # 计算熵
            result -= p * np.log2(p)
        return result
    # 计算条件熵
    def calcHDA(feature, label, index, value):
        '''
        计算信息熵
        :param feature:数据集中的特征,类型为ndarray
        :param label:数据集中的标签,类型为ndarray
        :param index:需要使用的特征列索引,类型为int
        :param value:index所表示的特征列中需要考察的特征值,类型为int
        :return:信息熵,类型float
        '''
        count = 0
        # sub_feature和sub_label表示根据特征列和特征值
        #分割出的子数据集中的特征和标签
        sub_feature = []
        sub_label = []
        for i in range(len(feature)):
            if feature[i][index] == value:
                count += 1
                sub_feature.append(feature[i])
                sub_label.append(label[i])
        pHA = count / len(feature)
        e = calcInfoEntropy(sub_feature, sub_label)
        return pHA * e
    #######请计算信息增益############
    #*********** Begin ***********#
    values = []#定义一个列表存放index列,即特征列的所有特征
    for i in range(len(feature)):
        values.append(feature[i][index])
    values_list = set(values)#创建一个无序不重复的元素集
    g = calcInfoEntropy(feature, label)#计算总熵
    for i in values_list:
        g -= calcHDA(feature, label, index, i)#总熵-每个特征的条件熵
    return g#得到信息增益
    #*********** End *************#

第一关:为什么要有训练集与测试集

1.B
2.A C

第3关:使用ID3算法构建决策树

任务描述

本关任务:复习课本,补充python代码,完成DecisionTree类中的fit和predict函数。

import numpy as np
class DecisionTree(object):
    def __init__(self):
        #决策树模型
        self.tree = {}
    def calcInfoGain(self, feature, label, index):
        '''
        计算信息增益
        :param feature:测试用例中字典里的feature,类型为ndarray
        :param label:测试用例中字典里的label,类型为ndarray
        :param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。
        :return:信息增益,类型float
        '''
        # 计算熵
        def calcInfoEntropy(label):
            '''
            计算信息熵
            :param label:数据集中的标签,类型为ndarray
            :return:信息熵,类型float
            '''
            label_set = set(label)
            result = 0
            for l in label_set:
                count = 0
                for j in range(len(label)):
                    if label[j] == l:
                        count += 1
                # 计算标签在数据集中出现的概率
                p = count / len(label)
                # 计算熵
                result -= p * np.log2(p)
            return result
        # 计算条件熵
        def calcHDA(feature, label, index, value):
            '''
            计算信息熵
            :param feature:数据集中的特征,类型为ndarray
            :param label:数据集中的标签,类型为ndarray
            :param index:需要使用的特征列索引,类型为int
            :param value:index所表示的特征列中需要考察的特征值,类型为int
            :return:信息熵,类型float
            '''
            count = 0
            # sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签
            sub_feature = []
            sub_label = []
            for i in range(len(feature)):
                if feature[i][index] == value:
                    count += 1
                    sub_feature.append(feature[i])
                    sub_label.append(label[i])
            pHA = count / len(feature)
            e = calcInfoEntropy(sub_label)
            return pHA * e
        base_e = calcInfoEntropy(label)#信息熵
        f = np.array(feature)
        # 得到指定特征列的值的集合
        f_set = set(f[:, index])
        sum_HDA = 0
        # 计算条件熵
        for value in f_set:
            sum_HDA += calcHDA(feature, label, index, value)
        # 计算信息增益
        return base_e - sum_HDA
    # 获得信息增益最高的特征
    def getBestFeature(self, feature, label):
      
        max_infogain = 0
        best_feature = 0
        #每一列
        for i in range(len(feature[0])):
            infogain = self.calcInfoGain(feature, label, i) #计算每一个特征的信息增益
            if infogain > max_infogain:
                max_infogain = infogain
                best_feature = i
        return best_feature
    def createTree(self, feature, label):
        # 1.所有的标签相同,样本里都是同一个label没必要继续分叉了
        if len(set(label)) == 1:
            return label[0]
        # 2.样本中只有一个特征或者所有样本的特征都一样的话就看哪个label的票数高
        if len(feature[0]) == 1 or len(np.unique(feature, axis=0)) == 1:
            vote = {}
            #为不同的label投票,计算数量最高的label
            for l in label:
                if l in vote.keys():
                    vote[l] += 1
                else:
                    vote[l] = 1
            #求vote中计数最高的label
            max_count = 0
            vote_label = None
            for k, v in vote.items():
                if v > max_count:
                    max_count = v
                    vote_label = k
            return vote_label
        # 3.第三种情况,根据信息增益拿到特征的索引
        best_feature = self.getBestFeature(feature, label)
        #创建树,根结点为信息增益最大的特征索引
        tree = {best_feature: {}}
        f = np.array(feature)
        # 拿到bestfeature的所有特征值
        f_set = set(f[:, best_feature])
        # 构建对应特征值的子样本集sub_feature, sub_label
        for v in f_set:
            sub_feature = []
            sub_label = []
            for i in range(len(feature)):
                #在此特征的此样本条下构建子树
                if feature[i][best_feature] == v:
                    sub_feature.append(feature[i])
                    sub_label.append(label[i])
            # 递归构建决策树
            tree[best_feature][v] = self.createTree(sub_feature, sub_label)
        return tree
    def fit(self, feature, label):
        '''
        :param feature: 训练集数据,类型为ndarray
        :param label:训练集标签,类型为ndarray
        :return: None
        '''
        #************* Begin ************#
        self.tree = self.createTree(feature,label)
        #************* End **************#
    def predict(self, feature):
        '''
        :param feature:测试集数据,类型为ndarray
        :return:预测结果,如np.array([0, 1, 2, 2, 1, 0])
        '''
        #************* Begin ************#
        
        def classify(tree, feature):
            #如果tree是叶子结点,也就不是字典类型,返回结点
            if not isinstance(tree, dict):
                return tree
            #tree.items()返回可遍历的(键, 值) 元组数组。
            t_index, t_value = list(tree.items())[0]
            #t_index:树根特征对应feature的index,eg:feature[4,3,1,0]
            f_value = feature[t_index]#最优信息增益index对应的特征值
            if isinstance(t_value, dict):#如果tree是叶子结点,继续分叉
                value = classify(tree[t_index][f_value], feature)#递归此结点后面的树
                return value
            #最后一个,叶子结点,对应的为标签值
            else:
                return t_value
        label = []
        for f in feature:         
            #添加通过决策树模型找到的叶子结点
            label.append(classify(self.tree, f))
        return np.array(label)
        #************* End **************#

第4关:信息增益率

任务描述

本关任务:根据所学知识,完成calcInfoGainRatio函数。

import numpy as np

def calcInfoGain(feature, label, index):
    '''
    计算信息增益
    :param feature:测试用例中字典里的feature,类型为ndarray
    :param label:测试用例中字典里的label,类型为ndarray
    :param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。
    :return:信息增益,类型float
    '''
    # 计算熵
    def calcInfoEntropy(label):
        '''
        计算信息熵
        :param label:数据集中的标签,类型为ndarray
        :return:信息熵,类型float
        '''

        label_set = set(label)
        result = 0
        for l in label_set:
            count = 0
            for j in range(len(label)):
                if label[j] == l:
                    count += 1
            # 计算标签在数据集中出现的概率
            p = count / len(label)
            # 计算熵
            result -= p * np.log2(p)
        return result

    # 计算条件熵
    def calcHDA(feature, label, index, value):
        '''
        计算信息熵
        :param feature:数据集中的特征,类型为ndarray
        :param label:数据集中的标签,类型为ndarray
        :param index:需要使用的特征列索引,类型为int
        :param value:index所表示的特征列中需要考察的特征值,类型为int
        :return:信息熵,类型float
        '''
        count = 0
        # sub_label表示根据特征列和特征值分割出的子数据集中的标签
        sub_label = []
        for i in range(len(feature)):
            if feature[i][index] == value:
                count += 1
                sub_label.append(label[i])
        pHA = count / len(feature)
        e = calcInfoEntropy(sub_label)
        return pHA * e

    base_e = calcInfoEntropy(label)
    f = np.array(feature)
    # 得到指定特征列的值的集合,:表示获取所有行
    f_set = set(f[:, index])#将不重复的特征值获取出来(比如:男,女)
    sum_HDA = 0
    # 计算条件熵
    for value in f_set:
        sum_HDA += calcHDA(feature, label, index, value)
    # 计算信息增益
    return base_e - sum_HDA


def calcInfoGainRatio(feature, label, index):
    '''
    计算信息增益率
    :param feature:测试用例中字典里的feature,类型为ndarray
    :param label:测试用例中字典里的label,类型为ndarray
    :param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。
    :return:信息增益率,类型float
    '''

    #********* Begin *********#
    up = calcInfoGain(feature, label, index)#信息增益率的分子
    #定义一个方法求分母中某个类型的个数(如求当v=1时表示性别为男的)
    def dcon(feature,value):
        s = 0
        for i in range(len(feature)):
            if feature[i][index] == value:
                s += 1
            else:
                pass
        return s      
    
    down = 0
    #取出特征值该列所有数据
    values = []
    for i in range(len(feature)):
        values.append(feature[i][index])
    values_set = set(values)#使用set()过滤重复值,得到特征值列中所有类型(如性别中男和女)
    #循环递归求出分母
    for value in values_set:
        down -= (dcon(feature,value)/len(feature)) * np.log2(dcon(feature,value)/len(feature))
    #求得信息增益率
    gain = up/down
    return gain
    #********* End *********#

第5关:预剪枝与后剪枝

1.B D
2.A

第6关:sklearn中的决策树

任务描述

本关任务:使用sklearn完成鸢尾花分类任务

from sklearn.tree import DecisionTreeClassifier

def iris_predict(train_sample, train_label, test_sample):
    '''
    实现功能:1.训练模型 2.预测
    :param train_sample: 包含多条训练样本的样本集,类型为ndarray
    :param train_label: 包含多条训练样本标签的标签集,类型为ndarray
    :param test_sample: 包含多条测试样本的测试集,类型为ndarry
    :return: test_sample对应的预测标签
    '''
    
    # ************* Begin ************#
    clf = DecisionTreeClassifier(criterion='entropy',max_depth=3)
    clf.fit(train_sample, train_label)
    result = clf.predict(test_sample)
    return result
    # ************* End **************#

你可能感兴趣的:(educoder,机器学习,机器学习,决策树,python,人工智能,算法)