决策树ID3的实现-python

import numpy as np
import pandas as pd

# 创造数据集
def createDataSet():
    data_row = {
        'no surfacing': [1, 1, 1, 0, 0],
        'flippers': [1, 1, 0, 1, 1],
        'fish': ['yes', 'yes', 'no', 'no', 'no']
    }
    dataSet = pd.DataFrame(data_row)
    return dataSet

# 计算香农熵,为了计算熵
def calcShannonEnt(dataSet):
    '''
    计算香农熵
    :param dataSet: 原始数据集
    :return: ent:香农熵的值
    '''
    n = dataSet.shape[0]  # 数据集总行数
    iset = dataSet.iloc[:, -1].value_counts()  # 标签的所有类别
    p = iset / n  # 每一类标签所占比
    ent = (-p * np.log2(p)).sum()  # 计算信息熵
    return ent

# 按照给定的特征划分数据集
def splitDataSet(dataSet, axis, value):
    '''
    :param dataSet: 待划分数据集
    :param axis: 指定的列序号
    :param value: 指定的属性的值
    :return: 按照指定的列索引和属性值切分后的数据集
    '''
    col = dataSet.columns[axis]  # 获得该序号对应的特征名
    rrdataSet = dataSet.loc[dataSet[col] == value, :]  # 获得属性col==value时的数据集
    redataSet = rrdataSet.drop(col, axis=1)  # 去掉指定的划分属性那一列
    return redataSet

# 选择最优的列进行切分
def chooseBestFeatureToSplit(dataSet):
    baseShannon = calcShannonEnt(dataSet)  # 计算初始的香农熵
    bestGain = 0  # 初始化信息增益
    bestFeatureIndex = -1  # 初始化最佳切分列
    for i in range(dataSet.shape[1] - 1):#对特征的每一列进行循环
        values=dataSet.iloc[:,i].value_counts().index#取出当前列的所有取值
        newShannon = 0.0
        for value in values:
            subDataSet = splitDataSet(dataSet, i, value)  # 利用不同的特征以及该特征的不同的取值划分数据集
            # 求新划分的数据集的香农熵
            prob = float(len(subDataSet)) / float(len(dataSet))
            newShannon += prob * calcShannonEnt(subDataSet)
        infoGain = baseShannon - newShannon  # 计算当前列的信息增益
        print(dataSet.columns[i],'划分数据集后的信息增益为:',infoGain)
        if (infoGain > bestGain):
            bestGain = infoGain
            bestFeatureIndex = i
    print('最高的信息增益为:',bestGain)
    return bestFeatureIndex
'''
# 没用到!
# 多数表决法定义叶子结点的分类
import operator
def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 1
        else:
            classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount
'''


# 递归构建决策树
def createTree(dataSet, featuresNames):
    print('========开始计算该结点是否需要划分========')
    print('目前的数据集为:')
    print(dataSet)
    print('目前的特征为::',featuresNames)
    classList = dataSet.iloc[:, -1].value_counts()#最后一列的类标签的统计
    #print(classList.index)
    #print(classList.index[0])
    decisionTree={}
    #递归出口:判断最多的标签数目(no 是3)是否等于数据集行数,或者数据集是否只有一列
    if classList[0] == dataSet.shape[0] or dataSet.shape[1] == 1:
        print('==========此处不需要划分!==========')
        return classList.index[0]  # 返回该类标签
    #开始创建决策树
    bestFeatureIndex=chooseBestFeatureToSplit(dataSet)#选择出划分数据集最好的特征的序号
    bestFeatureName=featuresNames[bestFeatureIndex]#根据序号获得属性名
    print('划分数据集最好的特征为:',  bestFeatureName)
    decisionTree={bestFeatureName:{}}#将该特征作为树的根节点
    del featuresNames[bestFeatureIndex]#将已放进树中的特征从特征中删除
    bestFeatureValues=set(dataSet.iloc[:, bestFeatureIndex])#提取所有样本关于这个特征的取值的不同取值
    #print('删除已放进树中的特征后,特征集合为:',featuresNames)
    #print('所有样本关于这个特征的取值:',bestFeatureValues)
    #递归式
    for value in bestFeatureValues:
        subFeaturesNames=featuresNames[:]#前几行中已经删除了最佳特征
        decisionTree[bestFeatureName][value]=\
            createTree(splitDataSet(dataSet,bestFeatureIndex,value),subFeaturesNames)
    return decisionTree


#使用决策树对一个实例分类
def classify(inputTree, attributes, testVector):
    '''
    :param inputTree: 已经生成的决策树
    :param attributes:训练集的所有属性(所有列)
    :param testVector: 测试数据,顺序对应训练集
    :return: 分类结果
    '''
    #firstNode,=inputTree.keys()#获取决策树第一个节点
    firstNode=next(iter(inputTree))
    #print('决策树第一个节点:',firstNode)
    secondDict=inputTree[firstNode]#下一个字典
    #print('secondDict:', secondDict)
    featureIndex=attributes.index(firstNode)#第一个结点所在的索引
    for key in secondDict.keys():
        if testVector[featureIndex]==key:
            if type(secondDict[key]).__name__=='dict':
                classLabel=classify(secondDict[key],attributes,testVector)
            else:
                classLabel=secondDict[key]
    return classLabel


if __name__ == '__main__':
    dataSea=createDataSet()#数据集
    attributes = list(dataSea.columns) #所有属性
    featuresNames=attributes[0:2]#特征
    train = dataSea#训练集
    decisionTree=createTree(dataSea,featuresNames)#建树
    np.save('models/decisionTree.npy',decisionTree)#保存树模型
    #loadDecisionTree=np.load('models/decisionTree.npy',allow_pickle=True).item()#保存之后可以直接加载模型使用
    print('========测试=======')
    # 对一个实例分类
    res1 = classify(decisionTree, attributes, [0,0])
    # 对一个数据集分类
    testVectors=[[0,0],[0,1],[1,0],[1,1]]
    result = []
    for test in testVectors:
        newres = classify(decisionTree, list(train.columns), test)
        result.append(newres)
    print(result)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值