【PYTHON机器学习】机器学习实战【决策树】扒代码

本文介绍了Python机器学习中决策树的实战应用,涵盖了数据集、信息熵概念,详细阐述了如何划分数据集及选择最佳划分方式。还分享了创建决策树的函数代码,并利用matplotlib进行可视化展示。后续将不断更新相关内容。
摘要由CSDN通过智能技术生成

喜欢可以关注【小猪课堂】公众号了解更多内容
在这里插入图片描述

from math import log
import pandas as pd 
import numpy as np

数据集

def createDataSet():
    dataSet=[[1,1,'yes'],
            [1,1,'yes'],
             [1,0,'no'],
            [0,1,'no'],
            [0,1,'no']]
    labels=['no surfacing','flippers','target']
    return dataSet ,labels

信息熵

def calcShannonEnt(dataSet):#注意使用这个函数时尽量是用numpy的形式不要直接将DataFrame直接写进去
    numEntries=len(dataSet)#数据集个数
    labelCounts={}#这是个字典,千万别认为是集合(以后后面会只用到key
    for featVec in dataSet: #其实我没有明白这个循环的意思,要是根据下面那个句代码来推断其实就是遍历说有的列
        currentLabel=featVec[-1]#选择target
        if currentLabel not in labelCounts.keys():#统计target中的个数
            labelCounts[currentLabel]=0#字典中 dict[key]=value
        labelCounts[currentLabel]+=1#字典中value的加法
    shannonEnt =0.0#定义熵为0 而且是float
    for key in labelCounts:#遍历所以的key
        prob = float(labelCounts[key])/numEntries#prob(概率)
        shannonEnt-=prob*log(prob,2)#这是使用统计学的熵函数
#     print(labelCounts)
    return shannonEnt#返回值可是供调用时用

划分数据集

# 如果是第一次看这个你可能有点蒙,但是看了多次后你会发现他只不过是一个非常简单。
#一列数据可能存在很多特征(类),然后将这这个特征选择出符合这个特征的数据子集
def splitDataSet(dataSet,axis,value):
    #数据集 :不解释
    #axis:就是在这个轴上(默认 axis=为列),我有点分不清axis=0/1
    #value:数值,其实这个值就跟这个轴上的类别差不多,也不是差不多就是一回事
    #将在数据集中某个轴上数值=x的数据筛选出来并保存为子集retDataSet
    retDataSet=[]#子集
    for featVec in dataSet:#遍历所有的列,包括target
        if featVec[axis] ==value:#如果这个列中的某一个值等于我们想要的目标值
            reduceFeatVac=featVec[:axis]#[0,1,2,3,4,x,6,7,8,n]  [:x)=[0,1,2,3,4]
            reduceFeatVac.extend(featVec[axis+1:])#[x=1:]=[6,7,8,n] 所以reducefeatvac中单独缺少x这个值[0,1,2,3,4,6,7,8,n]
            #存在一个问题就是'numpy.ndarray' object has no attribute 'extend'
            retDataSet.append(reduceFeatVac)#[[0,1,2,3,4,6,7,8,n],educefeatvac2,educefeatvac3,,]
    return retDataSet#返回子集列表

如何选择最好的划分方式

def chooseBestFeatureToSplit(dataSet):
    numFeatures=len(dataSet[0])-1#在理想的数据集中一般会把最后一列作为target,所以features的个数就是len(dataSet)个
    baseEntropy=calcShannonEnt(dataSet)#香农熵calcshannonent是一个我们定义的函数
    bestInfoGain=0.0#首先定义一个信息增益为0并且是float的数据类型
    bestFeature=-1#最好的特征为-1,这也包含了特殊值的处理
    for i in range(numFeatures):#遍历所有feature
        featList =[example[i] for example in dataSet]#产生某一特征的列表,不理解可以看下面的例子,理解可以略过
        #[example for example in mydat]
        #>>[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
        #[example[1] for example in mydat]
        #>>[1, 1, 0, 1, 1]
        uniqueVals=set(featList)#将featList列表变成集合,集合特征是将无序不重复,所以也就意味着已经将featList中变成没有冲服相的特征
        newEntropy=0.0#新的信息增益,并且float数据类型
        for value in uniqueVals:#变量特征中的类别,为求条件熵做数据准备
            subDataSet=splitDataSet(dataSet,i,value)#部分数据集,就是我上面跟大家讲的retdataset,叫条件子集比较好
            prob=len(subDataSet)/float(len(dataSet))#这个是权重比例就是\Dv\/\D\,不懂去看条件熵公式,不懂公式别着急看算法代码,这样很吃力
            newEntropy+=prob*calcShannonEnt(subDataSet)#这个好理解
        infoGain=baseEntropy-newEntropy#信息增益=信息熵-sum(条件熵)
        if (infoGain>beatInfogain):#信息增益的选择,选择出信息增益值醉大的分类作为最好的划分,增加数据纯度
            bestInfoGain=infoGain#最好的信息增益
            bestFeature=i#最好的划分属性
    return bestFeature#输出最好属性所在列的角标

创建树的函数代码

def majorityCnt(classList):
    classCount={}#类别汇总
    for vote in classList:#
        if vote not in classCount.keys(): classCount[vote] = 0#一、这种写法第一次见,二、这个逻辑非常聪明,将不存在的类别添加后赋值数量为0
        classCount[vote] += 1#在if循环外进行叠加
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)#降序
    #sorted(数据集,依据,排序)
    return sortedClassCount[0][0]#返回首列最大值
def createTree(dataSet,labels):#数据集和标签
    classList = [example[-1] for example in dataSet]#生成target结果list,这个地方能不能使用dataframe目前还不知道
        #[example for example in mydat]
        #>>[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
        #[example[1] for example in mydat]
        #>>[1, 1, 0, 1, 1]
    if classList.count(classList[0]) == len(classList):#最终含义就是,如果结果唯一怎么样
        #这个count()函数地方提现了这个作者代码功底的扎实,df.count()括号内没有内容是报错的,如果括号内有内容要书写统计的内容,
        #比如‘yes’就会返回在classlist中yes的个数
        return classList[0]#stop splitting when all of the classes are equal,返回类列表
    if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet,如果数据集中只有target数据没有变量
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)#最好的分类列
    bestFeatLabel = labels[bestFeat]#最好的特征名称
    myTree = {bestFeatLabel:{}}#
    del(labels[bestFeat])#从label中删除最好的特征值
    featValues = [example[bestFeat] for example in dataSet]#选择出最好的特征的list
    uniqueVals = set(featValues)#计算出最好特征下分存在多少类
    for value in uniqueVals:#遍历这些类后
        subLabels = labels[:]#copy all of labels, so trees don't mess up existing labels,相当于复制生成部分labels
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)#循环直到产生两个if条件为真
    return myTree#返回整个tree

使用matplotlib绘图

import matplotlib.pyplot as plt

decisionNode = dict(boxstyle="sawtooth", fc="0.8")#决策节点=字典(方框类型=锯齿型,fc是边框粗细)
leafNode = dict(boxstyle="round4", fc="0.8")#叶子节点=字典(方框类型=圆,)
arrow_args = dict(arrowstyle="<-")#arrow_args为箭头=字典(箭头类型arrowstyle=‘<-’)

def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    #定义结点图(nodeTxt用于记录nodeTxt,即节点的文本信息。centerPt表示那个节点框的位置。 parentPt表示那个箭头的起始位置。
    #nodeType表示的是节点的类型,也就会用我们之前定义的全局变量)
    createPlot.ax1.annotate(nodeTxt, xy=parentPt,  xycoords='axes fraction',xytext=centerPt, textcoords='axes fraction',
             va="center", ha="center", bbox=nodeType, arrowprops=arrow_args )
    #创建图片,ax1,annotate:注释((string)nodeTxt=注释文本, xy=注释位置,  xycoords='axes fraction',xytext=注释文本位置, 
    #textcoords='axes fraction',va=垂直对齐方式, ha=水平对齐方式, bbox=nodeType, arrowprops=arrow_args)
def createPlot():
    fig = plt.figure(1, facecolor='white')#创建一个图形
    fig.clf()#
    createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses 
    plotNode('a decision node', (0.5, 0.1), (0.1, 0.5), decisionNode)
    plotNode('a leaf node', (0.8, 0.1), (0.3, 0.8), leafNode)
    plt.show()
createPlot()

在这里插入图片描述
明天持续更新~
喜欢可以关注【小猪课堂】公众号了解更多内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值