python实现决策树

感谢

https://github.com/AliceDudu/Learning-Notes/blob/master/Machine-Learning-Algorithms/DecisionTrees/self-learning-c45algorithm-final.ipynb 

import os
import math
def createDataSet():
    """
    outlook->  0: sunny | 1: overcast | 2: rain
    temperature-> 0: hot | 1: mild | 2: cool
    humidity-> 0: high | 1: normal
    windy-> 0: false | 1: true
    """
    dataSet = [[0, 0, 0, 0, 'N'],
               [0, 0, 0, 1, 'N'],
               [1, 0, 0, 0, 'Y'],
               [2, 1, 0, 0, 'Y'],
               [2, 2, 1, 0, 'Y'],
               [2, 2, 1, 1, 'N'],
               [1, 2, 1, 1, 'Y']]
    labels = ['outlook', 'temperature', 'humidity', 'windy']
    return dataSet, labels

def calcShannonEnt(dataSet):
    """
    输入:数据集
    输出:数据集的香农熵
    描述:计算给定数据集的香农熵;熵越大,数据集的混乱程度越大
    仅仅计算输入的数据集的标签的信息熵,表达了数据集的标签的混乱程度/纯度
    """
    num_samples=len(dataSet)
    # dataSet 为二维列表,len(dataSet)表示数据集中共有多少个训练样本
    # len(dataSet[0]) 表示训练样本中共包含多少维度的特征
    label_dict={}
    for i in range(num_samples):
        if dataSet[i][-1] not in label_dict:
            # print(dataSet[i][-1])
            label_dict[dataSet[i][-1]]=1
        else:
            label_dict[dataSet[i][-1]]+= 1
    shannonEnt=0.0
    for k,v in label_dict.items():
        shannonEnt+=-(v/num_samples)*math.log(v/num_samples,2)
    return shannonEnt

def chooseBestFeature(dataSet):
    '''
    :param dataSet: 对于输入的数据集求解最优的属性划分
    :return:
    '''
    num_features=len(dataSet[0])
    num_samples=len(dataSet)

    entropy=calcShannonEnt(dataSet)
    # 计算数据集的经验熵

    # 计算每个属性的条件熵
    condition_entropy=[0]*num_features
    for i in range(num_features):
        # 给出当前特征属性的所有取值
        temp_dict={}
        temp_line_dict={}
        # print('here features',i)
        for j in range(num_samples):
            if dataSet[j][i]==float('inf'):
                # 意味着实际上当前属性是无效的
                condition_entropy[i]=float('inf')
                break
            if dataSet[j][i] not in temp_dict:
                temp_dict[dataSet[j][i]]=1
                temp_line_dict[dataSet[j][i]]=[dataSet[j][:i]+dataSet[j][(i+1):]]
            else:
                temp_dict[dataSet[j][i]]+= 1
                temp_line_dict[dataSet[j][i]].append(dataSet[j][:i] + dataSet[j][(i + 1):])
        for k,v in temp_dict.items():
            # print(temp_line_dict[k])
            condition_entropy[i]+=(v/num_samples)*calcShannonEnt(temp_line_dict[k])
    # 选择信息增益最大的特征维度作为当前的划分属性
    compare=list(map(lambda x:entropy-x,condition_entropy))
    best=-100
    best_index=-1
    for index in range(num_features):
        if compare[index]>best:
            best=compare[index]
            best_index=index
    return best_index

def split_dataset(dataSet,index,value):
    '''
    :param dataSet: 待划分的数据集
    :param index: 根据信息增益最大的原则,求出来的将数据集进行最优化分的属性索引值,index从0开始
    :param value: 将当前的属性索引处取值为value的样本都取出来,构成划分后的数据集,此时将已知的属性维度数值变成负无穷
    :return: 划分后的数据集
    '''
    output=[]
    num_samples=len(dataSet)
    for i in range(num_samples):
        if dataSet[i][index]==value:
            dataSet[i][index]=float('inf')
            output.append(dataSet[i])
    return output
def major_out(dataSet):
    label_dict={}
    num_samples=len(dataSet)
    for i in range(num_samples):
        if dataSet[i][-1] not in label_dict:
            label_dict[dataSet[i][-1]]=1
        else:
            label_dict[dataSet[i][-1]] = 1
    max_num=-100
    major_label=''
    for k,v in label_dict.items():
        if v>max_num:
            max_num=v
            major_label=k
    return major_label

def buildTree(dataSet, labels):
    # 构建决策树的最终目的是为了给输入的数据分类一个标签,故而决策树的输出值是标签
    # print(dataSet)
    # 将决策树表示成嵌套字典的形式
    class_list=[sample[-1] for sample in dataSet]
    if len(list(set(class_list)))==1:
        # 如果当前的数据集中只有一个类别,则就将该类别输出
        return class_list[0]
    if len(list(set(dataSet[0])))==1:
        # 如果数据表中没有其他属性可以考虑, 则N也是树叶,按
        # 照少数服从多数的原则在树叶上标出所属类别
        return major_out(dataSet)
    # 否则,根据平均信息期望值E或GAIN值选出一个最佳属性
    # 作为节点N的测试属性,得到最佳属性的索引下标
    best_feat=chooseBestFeature(dataSet)
    feat_value=list(set([line[best_feat] for line in dataSet]))

    # {'outlook': {0: 'N', 1: 'Y', 2: {'windy': {0: 'Y', 1: 'N'}}}}
    # 构建多重字典以存储决策树

    myTree={labels[best_feat]:{}}

    for v in feat_value:
        # print('v',v)
        sub_dataset=split_dataset(dataSet,best_feat,v)
        # print('sub_dataset',sub_dataset)
        if sub_dataset is not None:
            myTree[labels[best_feat]][v]=buildTree(sub_dataset,labels)
    return myTree

def createTestSet():
    """
    outlook->  0: sunny | 1: overcast | 2: rain
    temperature-> 0: hot | 1: mild | 2: cool
    humidity-> 0: high | 1: normal
    windy-> 0: false | 1: true
    """
    testSet = [[0, 1, 0, 0],
               [0, 2, 1, 0],
               [2, 1, 1, 0],
               [0, 1, 1, 1],
               [1, 1, 0, 1],
               [1, 0, 1, 0],
               [2, 1, 0, 1]]
    return testSet

def class_one_sample(test_sample,labels,Tree):
    temp_tree = Tree.copy()
    while (1):
        for k, v in temp_tree.items():
            temp_tree = temp_tree[k][
                test_sample[labels.index(k)]]  # {0: 'N', 1: 'Y', 2: {'windy': {0: 'Y', 1: 'N'}}}
            if isinstance(temp_tree, str):
                return temp_tree

def classify(testSet,labels,Tree):
    '''
    :param testSet: 测试数据集
    :param Tree: 根据训练数据集构建出来的决策树
            {'outlook': {0: 'N', 1: 'Y', 2: {'windy': {0: 'Y', 1: 'N'}}}}
    :param labels: 特征属性的名称
    :return:
    '''
    num_samples=len(testSet)
    num_feat=len(labels)
    output=[0 for _ in range(num_samples)]
    for i in range(num_samples):
        output[i]=class_one_sample(testSet[i],labels,Tree)
    return output




if __name__=='__main__':
    dataSet, labels=createDataSet()
    tree=buildTree(dataSet,labels)
    print(tree)
    # {'outlook': {0: 'N', 1: 'Y', 2: {'windy': {0: 'Y', 1: 'N'}}}}
    # print(calcShannonEnt(dataSet))
    # print(chooseBestFeature(dataSet))
    testSet=createTestSet()
    print(classify(testSet,labels,tree))
    # ['N', 'N', 'Y', 'N', 'Y', 'Y', 'N']

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值