决策数—(ID3和C4.5)算法实现

1.ID3算法

在这里插入图片描述
我们要对这样一组数据来构建一棵决策树来预测在{天气=晴,温度=适中,湿度=正常,风速=弱}的情况下,是否适合活动。

信息熵为: E n t ( ′ 活 动 ′ ) = − 9 14 l o g 2 9 14 − 5 14 l o g 2 5 14 = 0.9402859586706309 Ent('活动')=-{\frac{9}{14}log_{2}\frac{9}{14}}-\frac{5}{14}log_{2}\frac{5}{14}=0.9402859586706309 Ent()=149log2149145log2145=0.9402859586706309
信息增益的计算:
I n f o ′ 天 气 ′ ( ′ 活 动 ′ ) = 5 14 i n f o ′ 晴 ′ ( ′ 活 动 ′ ) + 4 14 i n f o ′ 雨 ′ ( ′ 活 动 ′ ) + 5 14 i n f o ′ 阴 ′ ( ′ 活 动 ′ ) = 5 14 ( − 3 5 l o g 2 3 5 − 2 5 l o g 2 2 5 ) + 4 14 ( − 4 4 l o g 2 4 4 − 0 0 l o g 2 0 0 ) + 5 14 ( − 2 5 l o g 2 3 5 − 3 5 l o g 2 3 5 ) = 0.6935361388961918 Info_{'天气'}('活动')=\frac{5}{14}info_{'晴'}('活动')+\frac{4}{14}info_{'雨'}('活动')+\frac{5}{14}info_{'阴'}('活动')=\frac{5}{14}(-\frac{3}{5}log_{2}\frac{3}{5}-\frac{2}{5}log_{2}\frac{2}{5})+\frac{4}{14}(-\frac{4}{4}log_{2}\frac{4}{4}-\frac{0}{0}log_{2}\frac{0}{0})+\frac{5}{14}(-\frac{2}{5}log_{2}\frac{3}{5}-\frac{3}{5}log_{2}\frac{3}{5})=0.6935361388961918 Info()=145info()+144info()+145info()=145(53log25352log252)+144(44log24400log200)+145(52log25353log253)=0.6935361388961918
信息增益为:Gain(‘天气’)=Ent(‘活动’)- i n f o I n f o ′ 天 气 ′ ( ′ 活 动 ′ ) = 0.2467498197744391 infoInfo_{'天气'}('活动')=0.2467498197744391 infoInfo()=0.2467498197744391
同理可以算出剩余三项的条件熵和信息增益分别为

i n f o A ( D ) info_{A}(D) infoA(D)Gain(A)
0.91106339301167630.029222565658954647
0.78845045730828960.15183550136234136
0.89215892826236170.04812703040826927

由此可以看出天气的信息增益最大,所以选择天气作为最优解,接下来数据集根据天气的不同被划分了三个部分:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
紧接着对每个子数据集重复上面的步骤,构造出对应的子决策树。

from math import log
import operator
import pickle
dataSet = [['sunny','hot','high','weak','no'],
           ['sunny','hot','high','strong','no'],
            ['overcast','hot','high','weak','yes'],
            ['rain','mild','high','weak','yes'],
            ['rain','cool','normal','weak','yes'],
            ['rain','cool','normal','strong','no'],
            ['overcast','cool','normal','strong','yes'],
            ['sunny','mild','high','weak','no'],
            ['sunny','cool','normal','weak','yes'],
            ['rain','mild','normal','weak','yes'],
            ['sunny','mild','normal','strong','yes'],
            ['overcast','mild','high','strong','yes'],
            ['overcast','hot','normal','weak','yes'],
            ['rain','mild','high','strong','no']]
labels = ['outlook','temperature','humidity','wind']
featlist=[number[0] for number in dataSet]
uniquelVals=set(featlist)
print(uniquelVals)
{'overcast', 'rain', 'sunny'}
def calcShanonEnt(dataset):#计算信息熵
    numSamples=len(dataset)
    labelCounts={}
    for fearture in dataset:#统计最后一列各标签的数目
        currentLabel=fearture[-1]
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1
    #print(labelCounts)
    entropy=0
    #计算信息熵
    for key in labelCounts:
        p=float(labelCounts[key])/numSamples
        entropy-=p*log(p,2)
    return entropy
calcShanonEnt(dataSet)
0.9402859586706309
def splitDataSet(dataSet,axis,value):
    retDataSet=[]
    for feat in dataSet:
        if feat[axis]==value:
            reduceFeat=feat[:axis]
            reduceFeat.extend(feat[axis+1:])
            retDataSet.append(reduceFeat)
    return retDataSet #返回不含划分特征的子集
splitDataSet(dataSet,0,'rain')
[['mild', 'high', 'weak', 'yes'],
 ['cool', 'normal', 'weak', 'yes'],
 ['cool', 'normal', 'strong', 'no'],
 ['mild', 'normal', 'weak', 'yes'],
 ['mild', 'high', 'strong', 'no']]
def chooseBestFeatureToSplit(dataSet):
    numberFeature=len(dataSet[0])-1#不选择标签列
    baseEntropy=calcShanonEnt(dataSet)#计算最后一列信息熵
    bestInforGain=0
    bestFeature=-1

    for i in range(numberFeature):
        featlist=[number[i] for number in dataSet]
        uniquelVals=set(featlist)
        #set 得到无重复的属性 {'rain', 'sunny', 'overcast'}

        newEntropy=0
        for vals in uniquelVals:
            subDataSet=splitDataSet(dataSet,i,vals)
            prob=len(subDataSet)/float(len(dataSet))
            newEntropy+=prob*calcShanonEnt(subDataSet)#计算条件增益
        inforGain=baseEntropy-newEntropy
        
        if(inforGain>bestInforGain):
            bestInforGain=inforGain
            bestFeature=i
    return bestFeature
#创建递归树,用于找出出现次数最多的分类名称
def majorityCnt(classList):
    classCount={}
    for vote in classList:#统计各特征值出现的次数
        if vote not in classCount.keys():
            classCount[vote]=0
        classCount[vote]+=1
   #对特征值出现的次数进行排序 
sortedClasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClasscount[0][0]
def creatTree(dataSet,labels):
    #存放最后一列
    classList=[example[-1] for example in dataSet]
    
    #count 统计某个元素出行的次数
   
    if classList.count(classList[0])==len(classList):
        return classList[-1]
    #当class里面全是一类是停止分割(即全为yes或者no的时候)

    if len(dataSet[0])==1: #当没有更多特征时停止分割,即分到最后一个特征也没有把数据完全分开,就返回多数的那个结果
        return majorityCnt(classList)
    
    #选出最优特征
    bestFeat=chooseBestFeatureToSplit(dataSet)
    bestFeatLable=labels[bestFeat]
    #从标签中取出最优特征对应的标签

    myTree={bestFeatLable:{}}
    del (labels[bestFeat])#删除已经找到的特征标签

    featValues=[example[bestFeat] for example in dataSet]
    #对特征标签每个值对应的样本进行划分
    uniquelVals=set(featValues)
    for value in uniquelVals:
        subLables=labels[:]
       #对每个划分出的子样本进行决策树构建
    subDataSet=splitDataSet(dataSet,bestFeat,value)
        myTree[bestFeatLable][value]=creatTree(subDataSet,subLables)
    return myTree
    
mytree=creatTree(dataSet,labels)
mytree
{'outlook': {'overcast': 'yes',
  'rain': {'wind': {'strong': 'no', 'weak': 'yes'}},
  'sunny': {'humidity': {'high': 'no', 'normal': 'yes'}}}}
labels = ['outlook','temperature','humidity','wind']
featlabels=labels[:]
testFeatValue=['rain','hot','high','weak']
def classify(tree,featlabels,testFeatValue):
    firstStr=list(tree.keys())[0]#outlook
    secondDict=tree[firstStr]#{'rain': {'wind': {'strong': 'no', 'weak': 'yes'}},
    # 'sunny': {'humidity': {'normal': 'yes', 'high': 'no'}}, 'overcast': 'yes'}
    featIndex=featlabels.index(firstStr)# 0 找出第一个标签的索引的位置
    # print(firstStr)
    # print(secondDict)
    # print(featIndex)
    for firstStr_value in secondDict.keys():
        if(testFeatValue[featIndex]==firstStr_value):
            #如果找到了对应分支,如果还有子树,则继续递归寻找
            if(type(secondDict[firstStr_value]).__name__=='dict'):##这里是两个 _
                classLabel=classify(secondDict[firstStr_value],featlabels,testFeatValue)
            else:
                classLabel=secondDict[firstStr_value]
    return classLabel

classify=classify(mytree,featlabels,testFeatValue)
print(classify)

yes
tinydict = {'Name': 'Zara', 'Age': 7}
tinydict.keys()
type(tinydict).__name__
'dict'
C4.5

C4.5是ID3算法的一个改进,他是基于增益率来选择最优特征的,而计算增益率则要在ID3的基础上求解特征熵,所以我们的C4.5 仅需在ID3的求信息熵函数和选择最优特征的函数上做些修改即可。

import operator
from math import log

dataSet = [['sunny','hot','high','weak','no'],
           ['sunny','hot','high','strong','no'],
            ['overcast','hot','high','weak','yes'],
            ['rain','mild','high','weak','yes'],
            ['rain','cool','normal','weak','yes'],
            ['rain','cool','normal','strong','no'],
            ['overcast','cool','normal','strong','yes'],
            ['sunny','mild','high','weak','no'],
            ['sunny','cool','normal','weak','yes'],
            ['rain','mild','normal','weak','yes'],
            ['sunny','mild','normal','strong','yes'],
            ['overcast','mild','high','strong','yes'],
            ['overcast','hot','normal','weak','yes'],
            ['rain','mild','high','strong','no']]
labels = ['outlook','temperature','humidity','wind']
classList=[example[-1] for example in dataSet]
print(dataSet[0])
len(dataSet[0])
['sunny', 'hot', 'high', 'weak', 'no']





5
#不仅可以求解信息熵,还可以求解每个特征的特征熵
def clacShanonEntFeature(dataSet,i):
    numbers=len(dataSet)
    labelCounts={}
    for feature in dataSet:
        currentlabel=feature[i]
        if currentlabel not in labelCounts.keys():
            labelCounts[currentlabel]=0
        labelCounts[currentlabel]+=1
    #统统不同特征取值对应的个数
    entropy=0
    for key in labelCounts:
        p=float(labelCounts[key])/numbers
        entropy-=p*log(p,2)
    return entropy
clacShanonEntFeature(dataSet,0)

1.5774062828523452
def splitDataSet(dataSet,axis,value):
    Redataset=[]
    for feature in dataSet:
        if(feature[axis]==value):
            reduceset=feature[:axis]
            reduceset.extend(feature[axis+1:])
            Redataset.append(reduceset)
    return Redataset
splitDataSet(dataSet[:],0,'rain')
#分割不含最优特征的子数据集
[['mild', 'high', 'weak', 'yes'],
 ['cool', 'normal', 'weak', 'yes'],
 ['cool', 'normal', 'strong', 'no'],
 ['mild', 'normal', 'weak', 'yes'],
 ['mild', 'high', 'strong', 'no']]
def chooseBestFeature(Dataset):
    baseEntropy=clacShanonEntFeature(dataSet,-1)
    bestFeature=-1
    bestGrainrate=0
    numbersFeature=len(Dataset[0])-1
    for i in range(numbersFeature):
        featurelist=[example[i] for example in dataSet]
        uniquefeature=set(featurelist)
        newEntropy=0
        for uniquevalue in uniquefeature:
            #求各个特征条件熵
            subDataSet=splitDataSet(dataSet,i,uniquevalue)
            p=float(len(subDataSet))/len(Dataset)
            newEntropy+=p*clacShanonEntFeature(subDataSet,-1)

        infroGain=baseEntropy-newEntropy#求增益

        splitInfo=clacShanonEntFeature(dataSet,i)
        if(splitInfo==0):#如果分母为0跳过
            continue
        else:
            Grainrate=infroGain/splitInfo#求解增益率
        
        if(Grainrate>bestGrainrate):
            bestGrainrate=Grainrate
            bestFeature=i
    return bestFeature
#dataSet
chooseBestFeature(dataSet)
0
def majorityCnt(classList):
    classCount={}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
        else:
            classCount[vote]+=1
    sortedClasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClasscount[0][0]
def creatTree(dataSet,labels):
    classList=[example[-1] for example in dataSet]

    if(classList.count(classList[0])==len(classList)):
        return classList[0]
    #如果样本输出类别为同一类Di,直接返回Di
    if(len(dataSet[0])==1):
        return majorityCnt(classList)
    #如果样本特征为空,则返回类别为样本中输出类别D实列数最多的类别
    bestFeature=chooseBestFeature(dataSet)#选出最优特征
    bestLabel=labels[bestFeature]
    mytree={bestLabel:{}}

    del(labels[bestFeature])#删除一选出的特征标签

    featurevalues=[example[bestFeature] for example in dataSet]
    uniquevalues=set(featurevalues)#求出每个特征可以取得值
    for values in uniquevalues:
        sublabels=labels[:]#对每个子数据集进行递归求决策树
        subDataset=splitDataSet(dataSet,bestFeature,values)
        mytree[bestLabel][values]=creatTree(subDataset,sublabels)
    return mytree

creatTree(dataSet,labels)

{'outlook': {'rain': {'wind': {'no': 'no', 'yes': 'yes'}},
  'sunny': {'wind': {'no': 'no', 'yes': 'yes'}},
  'overcast': 'yes'}}

参考博客:
决策树之python实现ID3算法
决策树之python实现C4.5算法

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 实际销售金额。决策树适用于分类和预测问题,这里我们可以利用决策树来预测不同天气状况、是否周末、是否促销对销售金额的影响。 首先,我们需要通过Python的pandas库读取据集。使用pd.read_excel()函读取sales_data.xls文件,并将据存储在一个DataFrame中。 然后,我们需要对据进行预处理。首先,我们需要将文本类型的特征转换为值类型。可以使用pandas的get_dummies()函来进行独热编码,将天气、是否周末、是否促销这三个特征转换为值类型的特征。 接下来,我们将据集分为特征和标签。我们将天气、是否周末、是否促销作为特征X,将实际销售金额作为标签y。这样我们就可以将预测销售金额的问题转换为回归问题。 然后,我们可以通过sklearn库中的DecisionTreeRegressor类来构建决策树模型。首先,我们需要导入DecisionTreeRegressor类,并创建一个DecisionTreeRegressor对象。然后,使用fit()函拟合我们的据集。 接下来,我们可以使用训练好的模型来进行预测。可以使用predict()函来进行预测,传入特征X,得到预测的销售金额。 最后,我们可以通过与实际销售金额进行比较,评估我们的模型的准确性。可以使用sklearn库中的metrics模块来计算均方误差、均方根误差等指标,评估我们的模型。 通过上述步骤,我们可以利用决策树模型对销售据进行预测,并评估模型的准确性。这样就可以帮助企业更好地了解不同天气状况、是否周末、是否促销对销售金额的影响,从而优化销售策略。 ### 回答2: 决策树是一种常见的机器学习算法,可以用于解决分类和回归问题。在给定的据集中,包含了每天的销售据,以及每天的天气情况、是否是周末和是否有促销活动。 我们可以使用决策树来预测某一天的销售量,根据天气情况、是否是周末和是否有促销活动来进行分类。首先,我们需要将据集分为训练集和测试集,以便评估模型的性能。然后,我们可以使用scikit-learn库中的DecisionTreeClassifier类来构建决策树模型。 首先,我们需要读取据集sales_data.xls。然后,我们可以使用pandas库来处理据,将天气情况、是否是周末和是否有促销活动转换为值特征。 接下来,我们可以将据集分为输入特征和目标变量。输入特征为天气情况、是否是周末和是否有促销活动,目标变量为销售量。然后,我们将据集分为训练集和测试集。 然后,我们可以使用训练集来拟合决策树模型。可以设置一些参,例如树的最大深度和叶子节点的最小样本,以避免过拟合。 在模型训练完成后,我们可以使用测试集来评估模型的性能。可以使用一些评估指标,例如准确率、精确率和召回率来评估模型在预测销售量方面的表现。 最后,我们可以使用训练好的决策树模型来预测新的销售据。根据给定的天气情况、是否是周末和是否有促销活动,我们可以使用模型来预测销售量。 综上所述,决策树可以用于根据天气、是否是周末和是否有促销活动来预测销售量。通过构建决策树模型,我们可以根据特定的输入特征来进行分类,并预测销售量。在实际应用中,这可以帮助我们了解影响销售量的因素,并作出相应的决策

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值