数据挖掘十大算法(一):决策树算法 python和sklearn实现

2023-11-01

学完到第三章——决策树,python代码实现的仅是ID3算法,sklearn为优化过的C4.5,这里做一个详细的总结包括(原理、代码、可视化、scikit-learn实现),皆为亲自实践后的感悟。以下进入正文。

早前简单了解了决策树的原理,然后为了尽快使用便没有深究直接使用sklearn实现,虽然sklearn使用起来极其极其的方便,但是我还是想理解到其中的代码实现机制以及一些数学知识,所以在《机器学习实战》的第三章我结合它的思路用自己的代码实现了(香农熵、信息增益、创建决策树字典、可视化决策树)。思路和代码都不是很难,较容易理解。这样实践后最大的收获不仅是代码的编写能力,还有什么样的数据以及如何调整数据集才能更好的适用于决策树。(个人代码主要数据格式为DataFrame)

这里补充几个知识点

    1:数据集种类(目标变量)越多越复杂熵越大,所以原始数据的熵最大

    2:熵公式:   n代表X的n种不同的离散取值,pi代表X取值为i的概率,log以2或e为底的对数

    3:信息增益(简单处理):原始数据熵-目前特征的熵

 

决策树原理:(这里只是重点描述,决策树还是涉及很多知识的,详细请参考更多博文)

    1:求得每个特征的熵,与目前原始数据熵比较从而得到该特征的信息增益。

    2:从中选出信息增益最大的那个最优特征,将它取出来当作当前节点。

    3:排除当前节点,递归继续重复1、2步骤。

    4:两个条件结束3的递归。1:当前节点下目标变量唯一。 2:所有特征都循环完了。

上面的4点是创建决策树中最关键的点,也是其基本原理,围绕这四个点我们可以创建出简单的决策树,下面为代码段。

 

代码实现:

下面是创建的测试数据集,当然复杂的数据集都能实现,只要满足该DataFrame格式

from math import log
import pandas as pd
import numpy as np
#数据集种类越多越复杂熵越大

#创建数据集 (返回DataFrame)
def createdata():
    data = pd.DataFrame({'water':[1,1,1,0,0],'feet':[1,1,0,1,1],'survive':['yes','yes','no','no','no']})
    return data

#计算香农熵  (DataFrame)
def calculateshang(data):
    names = data[data.columns[-1]]      #依据公式求某列特征的熵 目标变量作为概率依据
    n = len(names)
    labels = {}
    for i,j in names.value_counts().items():
        labels[i] = j
    shang = 0
    for i in labels:            #利用循环求熵
        pi = labels[i]/n
        shang -= pi * log(pi,2)
    return shang

#划分数据集  (DataFrame,特征列名,该列某个特征值)
def splitdataSet(data,feature,feature_value):
    recvdata = []
    n = len(data)
    for i in range(n):          #如果该行的这个特征值==循环到的这个特征值,去掉该特征加入返回列表
        if(data.iloc[[i],:][feature].values[0] == feature_value):
            temp = data.iloc[[i],:]  #问题一:DataFrame如何取一行为Series,就可以直接drop了
            k = temp.index.values[0]
            temp_t = temp.ix[k]         #问题二:DataFrame为什么这里使用iloc或loc不行,明明我是按照位置取值的而非行号
            tem = temp_t.drop(feature)
            recvdata.append(tem)
    recvDF = pd.DataFrame(recvdata)     #将满足条件的所有行定义为DataFrame
    return recvDF

#得出最好的特征名,用来划分数据集 (DataFrame)
def choosebestfeaturetosplit(data):
    nameFeatures = data.columns
    baseEntropy = calculateshang(data)  #基础最大原始香农熵
    bestinfoGain = 0.0                  #初始化最好信息增益
    bestFeature = -1                    #初始化最好的特征名
    for Feature in nameFeatures[:-1]:   #循环所有特征
        uniquevalue = set(data[Feature])#该特征的所有唯一值
        newEntropy = 0.0            #中间熵
        for value in uniquevalue:
            subdata = splitdataSet(data,Feature,value)
            pi = len(subdata) / len(data)
            newEntropy += pi * calculateshang(subdata)
        infoGain = baseEntropy - newEntropy     #中间信息增益
        if(infoGain > bestinfoGain):
            bestinfoGain = infoGain
            bestFeature = Feature   #循环比较所有特征,返回信息增益最大的特征列名
    return bestFeature

#若创建数结束后目标变量仍不唯一,则以最多的一类为准  (Series)
def major_k(classlist):
    classcount = classlist.value_counts()
    result = classcount.sort_values(ascending=False).index[0]
    return result

#建立决策树  (DataFrame)(返回dict): {'water': {0: 'no', 1: {'food': {0: 'no', 1: 'yes'}}}}
def createtree(data):
    labels = data.columns
    classlist = data[labels[-1]]
    if(len(classlist.values) == classlist.value_counts()[0]):   #结束条件1:该分支目标变量唯一
        return classlist.values[0]
    if(len(labels) == 1):                          #结束条件2:所有特征名都循环完了
        return major_k(classlist)   #这里并不能直接返回目标变量名,可能不唯一,所以调用major_k
    bestFeature = choosebestfeaturetosplit(data)
    myTree = {bestFeature:{}}   #这里很巧妙,以此来创建嵌套字典
    unique = set(data[bestFeature])
    for value in unique:
        myTree[bestFeature][value] = createtree(splitdataSet(data,bestFeature,value))   #递归创建树
    return myTree

#分类器预测  (嵌套字典 列表特征名 列表测试数据)
def classfiy(myTree,labels,test):
    firstStr = list(myTree.keys())[0]       #需要获取首个特征的列号,以便从测试数据中取值比较
    secondDict = myTree[firstStr]           #获得第二个字典
    featIndex = labels.index(firstStr)      #获取测试集对应特征数值
    for key in secondDict.keys():
        if(test[featIndex] == key):
            if(type(secondDict[key]).__name__ == 'dict'):       #判断该值是否还是字典,如果是,则继续递归
                classlabel = classfiy(secondDict[key],labels,test)
            else:
                classlabel = secondDict[key]
    return classlabel

#画决策树pdf图   (DataFrame)
def showtree_pdf(data):
    from sklearn import tree    #导入sklearn的决策树模型(包括分类和回归两种)
    import pydotplus    #画句子的依存结构树

    a = data.iloc[:,:-1]    #特征矩阵
    b = data.iloc[:,-1]     #目标变量
    clf = tree.DecisionTreeClassifier() #分类决策树
    clf.fit(a,b)
    dot_data = tree.export_graphviz(clf, out_file=None) #利用export_graphviz将树导出为Graphviz格式
    graph = pydotplus.graph_from_dot_data(dot_data)
    graph.write_pdf("iris1.pdf")  #保存树图iris.pdf到本地

if __name__=="__main__":
    data = createdata() #创建数据集

    myTree = createtree(data)   #创建嵌套字典树
    print(myTree)

    result = classfiy(myTree,list(data.columns),[1,0])  #预测测试数据
    print(result)

    showtree_pdf(data)    #使用sklearn和pydotplus来画决策树,windows需要提前安装graphviz工具

下面结果第一行是嵌套字典格式的决策树,第二行为预测值(没问题)

下面是我使用sklearn构建的模型再用pydotplus库和graphviz绘制的pdf图,graphviz需要到这里下载msi来安装,然后添加系统路径。

讲讲这个决策树图的含义(很多人的博客抄袭别人就是画个图,我感觉他都不知道这个图什么意思。。。由于没找到参考,以下个人理解总结):

    1:X[0]表示第一个节点特征(这里为water)的值,<=0.5(特征值)可以分为两类,目标变量不唯一的3个数据再判断X[1]第二个节点特征feet

    2:gini系数越小,不纯度越低,特征越好(叶子节点很纯gini=0)

    3:samples表示当前节点的样本数

    4:目标变量有多少个离散变量种类,value列表长度就多长(例如:no、yes为两个:[3个no,2个yes])

 

--------------------------------------------------------------------------------------------------------------------------------

好了以上便是有关决策树简单实现的所有内容,从头编写一次代码,理解底层原理,接触原始数据后基本算是决策树入门了,那么为了提高编码和工作效率我们可以使用sklearn来极为方便的实现。

sklearn决策树算法类库内部实现是使用了调优过的CART树算法,既可以做分类(DecisionTreeClassifier),又可以做回归(DecisionTreeRegressor),两者参数几乎一致,部分意义有差别。

C4.5为优化过的ID3算法,改进:

    1:用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性不足;

    2:在树构造过程中进行剪枝;

    3:能够完成对连续属性的离散化处理;

    4:能够对不完整数据进行处理。

这里我还会提到一个很方便、很爽的方法Categorical

    如果使用我上面编写的代码那么则可以处理数据特征为非数值型的特征值,但是如果要在sklearn中使用决策树模型那么则需要将没有大小的离散型值转换为数值如:[red,blue,yellow]->[0,1,2],这里我们使用Categorical可以轻松实现。下面是转换、画图完整代码。

原始数据:

代码:

import pandas as pd
import numpy as np
#数据集种类越多越复杂熵越大

#画决策树pdf图   (DataFrame)
def showtree_pdf(data):
    from sklearn import tree    #导入sklearn的决策树模型(包括分类和回归两种)
    import pydotplus    #画句子的依存结构树

    a = data.iloc[:,:-1]    #特征矩阵
    b = data.iloc[:,-1]     #目标变量
    clf = tree.DecisionTreeClassifier() #分类决策树
    clf.fit(a,b)    #训练
    dot_data = tree.export_graphviz(clf, out_file=None) #利用export_graphviz将树导出为Graphviz格式
    graph = pydotplus.graph_from_dot_data(dot_data)
    graph.write_pdf("iris4.pdf")  #保存树图iris.pdf到本地

def change(data):
    names = data.columns[:-1]
    for i in names:
        col = pd.Categorical(data[i])
        data[i] = col.codes
    print(data)

if __name__=="__main__":
    data = pd.read_table('lenses.txt',header=None,sep='\t') #读取文件
    change(data)        #转换非大小离散型为数值型
    showtree_pdf(data)  #画pdf图

看看转换后的数据:

再看看决策图pdf:

相当的简单方便,如果需要预测直接使用predict方法就行,当然模型里面有很多的参数可能需要调整,这也就是为什么我们需要深入了解底层的原理,这样能帮助我们理解如何去调参。参数博客参考

 

以上为全部内容,有问题还请还请指教。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据挖掘十大算法(一):决策树算法 python和sklearn实现 的相关文章

  • 默认情况下在 Jupyter 笔记本中配置第一个单元

    有没有办法为 Jupyter 笔记本中的特定 python 内核配置默认的第一个单元 我同意默认的 python 导入违背了良好的编码实践 那么 我可以配置笔记本 使新的 python 笔记本的第一个单元始终是 import numpy a
  • Ajax 调用后使用 Django 模板呈现 JSON 对象

    我一直在尝试了解什么是最佳方法Ajax http en wikipedia org wiki Ajax 28programming 29 in Django http en wikipedia org wiki Django 28web f
  • Python 将列表中的字符串转换为数字

    我遇到了以下错误消息 以 10 为基数的 int 的文字无效 2 2 外部用单引号括起来 内部用双引号括起来 该数据位于primes列出使用print primes 0 样本数据在primes list 2 3 5 7 The primes
  • 计算温度的偏导数(温度的水平平流)

    我想知道哪种方法计算x和y方向温度的偏导数 温度的水平平流 最正确 第二个代码使用温度 纬向风和经向风的数据矩阵 提取温度 T 纬向风分量 u 和经向风分量 v 的数据 import matplotlib pyplot as plt imp
  • Python中使用cv2获取当前视频播放位置

    我正在尝试使用 CV2 和 Python 从播放视频中获取当前播放时间位置 如果可能 以毫秒为单位 目前我正在使用此示例代码来播放视频文件 import cv2 import numpy as np file name 2 mp4 wind
  • Python 按文件夹模块导入

    我有一个目录结构 example py templates init py a py b py a py and b py只有一个类 名称与文件相同 因为它们是猎豹模板 纯粹出于风格原因 我希望能够在中导入和使用这些类example py像
  • 如何在 pygame 中聚焦光线或如何仅绘制窗口的某些圆形部分?

    对于这一点 如果您熟悉它 请想想 超级马里奥制造2 中嘘关卡中的黑暗模式 我试图在角色周围创建一个圆形聚光灯 这也将使圆圈范围内的任何内容都可见 例如部分站在地板上 敌人或场景中的任何其他物体 我的计划是首先绘制圆圈 聚光灯 然后绘制场景
  • Pygame 玩家精灵没有出现

    我一直在为学校计算机课做这个项目 但无法让玩家精灵出现 有人可以帮忙吗 当我运行主游戏循环时 除了玩家精灵之外 所有内容都正确显示 它应该由于箭头输入而在屏幕上移动并受到重力的影响 当我删除图像并仅使用对象类和矩形时 该代码也有效 impo
  • WTForms 中的小数字段舍入

    我有一个包含价格小数字段的表单 如下所示 from flask ext wtf import Form import wtforms from wtforms validators import DataRequired from deci
  • 肥皂服务的良好框架是什么?

    我正在寻找一个用于肥皂的好框架service 我更喜欢使用Pythonic框架 但是在查看了soaplib rpclib 太不稳定 SOAPy 不适用于2 7 和ZSI 太 令人困惑 之后 我不确定这是否可能 我对使用另一种语言感到满意 尽
  • 按字段名称对命名元组列表进行排序的 Pythonic 方法

    我想对命名元组列表进行排序 而不必记住字段名的索引 我的解决方案看起来相当尴尬 希望有人能有一个更优雅的解决方案 from operator import itemgetter from collections import namedtu
  • 对于 pygtk 应用程序来说,什么是好的嵌入式浏览器?

    我计划在我的 pygtk 应用程序中使用嵌入式浏览器 并且我正在 gtkmozembed 和 pywebkitgtk 之间进行辩论 两者之间有什么引人注目的区别吗 还有我不知道的第三种选择吗 应该注意的是 我不会使用它来访问网络上的内容 我
  • 如何将时间间隔划分为不同长度的部分?

    我有一个从 0 到t 我想把这个区间分成一个以2 25 2 25 1 5为周期的累积序列 方法如下 input start 0 stop 19 output sequence 0 2 25 4 5 6 8 25 10 5 12 14 25
  • 监控单个文件

    我需要监控 使用watchdog http pythonhosted org watchdog index html 单个文件 而不是整个目录 避免监视整个目录的最佳方法是什么 我想this http pythonhosted org wa
  • 避免在列表理解中计算相同的表达式两次[重复]

    这个问题在这里已经有答案了 我在列表理解中使用一个函数和一个 if 函数 new list f x for x in old list if f x 0 令我恼火的是这个表达f x 在每个循环中计算两次 有没有办法以更清洁的方式做到这一点
  • Python 类方法的示例用例是什么?

    我读了Python 中的类方法有什么用 https stackoverflow com questions 38238 what are class methods in python for但那篇文章中的例子很复杂 我正在寻找 Pytho
  • 安排 Asyncio 任务每 X 秒执行一次?

    我正在尝试创建一个 python 不和谐机器人 它将每隔 X 秒检查一次活跃会员 并根据会员的在线时间奖励积分 我正在使用 asyncio 来处理聊天命令 这一切都正常 我的问题是找到一种方法来安排每隔 X 秒异步检查一次活动成员 我已经阅
  • 在字典理解中为 locals() 添加下标失败并出现 KeyError [重复]

    这个问题在这里已经有答案了 我对 Python 的奇怪行为感到困惑locals 基本上我想从字典中获取一个项目locals 在字典理解中 但它失败了 这是一个非常基本的事情 所以 gt gt gt foo 123 gt gt gt bar
  • Networkx 中 Louvain 分区的可视化

    请帮助我更改 Louvain 聚类算法结果的可视化 我从网站上获取了代码https github com taynaud python louvain https github com taynaud python louvain我可以重写
  • 将 pandas 数据框中的多列更改为日期时间

    我有一个 13 列和 55 000 行的数据框 我正在尝试将其中 5 行转换为日期时间 现在它们返回类型 对象 我需要转换这些数据以进行机器学习 我知道如果我这样做 data birth date pd to datetime data b

随机推荐

  • Python副业兼职,月赚7800元,一天只要两小时 !

    现在学习python的人越来越多了 跟大家聊聊如何利用python搞副业赚钱 想要利用 Python 赚钱的方式还是比较多的 其中接单和投稿算是两种比较简单的方式了 如果你是业余学python爬虫 可以去淘宝上加了找了几个店铺直接问需要爬虫
  • 编译报错:TypeError: Cannot read property ‘styles‘ of undefined at Object.loader

    编译报错 TypeError Cannot read property styles of undefined at Object loader 如下图 因为我的vue loader的版本是17以上 太高了 需要降到15的版本 我重新下的版
  • vue 异步加载远程组件(支持编译less语法)

    本代码已组件化 可以直接使用 说明 本组件可以直接解析 vue文件 为了支持less语法解析 在组件中引入less js 可在less官网下载 组件代码
  • 戴尔r510服务器不显示,戴尔 服务器dell R510 与 dell R710 对比

    戴尔台式机DELL服务器R510与R710的区别 戴尔台式机DELL服务器R510和R710有好多相同之处 1 都是2U服务器 2 都是双CPU服务器 3 所用CPU都是INTEL5500系列CPU 4 所用内存也是同样型号 R410 R5
  • PTA(Basic Level) 1094 谷歌的招聘

    2004 年 7 月 谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌 如下图 用于招聘 内容超级简单 就是一个以 com 结尾的网址 而前面的网址是一个 10 位素数 这个素数是自然常数 e 中最早出现的 10 位连续数字 能找出这个
  • 【点云】Large-scale Point Cloud Semantic Segmentation with Superpoint Graphs

    目录 1 摘要 2 介绍 3 方法 3 1 基于全局能量的集合分割 3 2 建立超点图 3 3 嵌入超点 3 4上下文分割 1 摘要 我们提出一个基于深度学习的框架 来解决大规模点云的语义分割问题 我们认为点云的组织形式可以被SPG Sup
  • 简单了解单点登录及实现方案

    代码演示基于springboot 一 单应用单节点登录认证 任何一个应用系统都离不开登录认证过程 实现登录认证主要目的是对系统的权限管理 在单应用单节点下常用做法通常采用session认证机制 其主要流程如下 客户端访问登录接口 传递用户名
  • i219-v不支持服务器,网络适配器中找不到Intel(R) Ethernet Connection I219-V该怎么解决?在虚拟机配...

    是因为网络适配器权限问题 1 打开网络连接 如下图 2 打开本地连接的属性 选择高级菜单 并将Internet连接共享的勾都打上 3 然后选择无线网卡进行专用网络连接 4 设置之后 您可以看到本地连接有一个手形图标 表明它是一个共版享状态
  • 三极管饱和及深度饱和状态的理解和判断!

    三极管饱和问题总结 1 在实际工作中 常用Ib V R作为判断临界饱和的条件 根据Ib V R算出的Ib值 只是使晶体管进入了初始饱和状态 实际上应该取该值的数倍以上 才能达到真正的饱和 倍数越大 饱和程度就越深 2 集电极电阻 越大越容易
  • 单选按钮input[type=radio],加上disabled后按钮颜色失效,始终默认为灰色

    在前端使用单选按钮input type radio 时 渲染后台数据时将单选按钮设为不可修改 给input加上disabled后 按钮颜色变灰 且通过css修改样式也无法改变 通过百度尝试了类似以下方式的几种修改css样式的常用办法解决 但
  • 【Android学习】导入别人的Android项目到AS中

    更新 最好直接导入 有错误再根据对应错误修改 学习阶段 下载学习他人的项目是必不可少的一步 但是新手又常常会遇到各种奇葩的问题 问题不可怕 可怕是自己退缩 总结下自己的一些经验 望对后来的你有所帮助 一 快速更改 在移植别人项目之前 最好先
  • 华为机试题69-矩阵乘法

    描述 如果A是个x行y列的矩阵 B是个y行z列的矩阵 把A和B相乘 其结果将是另一个x行z列的矩阵C 矩阵的大小不超过100 100 输入描述 第一行包含一个正整数x 代表第一个矩阵的行数 第二行包含一个正整数y 代表第一个矩阵的列数和第二
  • 20210220--CTF小笔记之常见的md5碰撞

    欢迎大家一起来Hacking水友攻防实验室学习 渗透测试 代码审计 免杀逆向 实战分享 靶场靶机 求关注 0e开头的md5和原值 QNKCDZO 0e830400451993494058024219903391 s878926199a 0e
  • 小程序内嵌webview实现支付

    点击上方 青年码农 关注 回复 特效源码 可获取各种资料 目前的一个小程序项目需要把客户之前的h5页面嵌入到现在的小程序中 并且之前的支付功能要正常 小程序提供了webview开放能力供我们使用 但是不允许在webview直接调起微信支付
  • 重载的分析

    前言 在c 中 出现重载的概念 其实就是一个高级语言的象征 他的出现就是机器语言更加的自然化 他其实可以理解位我们自然语言中的动词 它可以和不同的名词起到不同的功能 重载 定义 用一个相同的函数名来定义不同的函数 重载的条件 参数的个数不同
  • CMSIS-RTOS的信号量使用备忘

    说明 因为要使用CMSIS RTOS的信号量 所以需要了解以下几点功能 1 接收信号量时 返回值的意思 2 接收信号量时 如果信号量容器不只为一 那么是否可以再次接收到 3 发送信号量是否有限制 带着以上问题做了一个测试程序 例一 程序代码
  • strace ltrace记录

    strace 安装 常用选项 报错 strace trace system calls and signals ltrace A library call tracer 安装 首次使用可能出现这个提示 就是没安装 yum y install
  • ubuntu 远程服务器文件与本地文件互传

    放在这里自学 cite https blog csdn net Iv zzy article details 109412198 1 从服务器下载文件到本地 scp r 远程服务器用户名 远程IP 需要下载的文件路径 本地存放文件路径 2
  • 金融分析与风险管理——资本资产定价模型

    金融分析与风险管理 资本资产定价模型 1 系统性风险与非系统性风险 2 资本资产定价模型 1 系统性风险与非系统性风险 在理论上 股票面临的风险可以抽象的划分为系统性风险与非系统性风险 系统性风险 不可分散风险 也称市场风险 通常是由于公司
  • 数据挖掘十大算法(一):决策树算法 python和sklearn实现

    学完到第三章 决策树 python代码实现的仅是ID3算法 sklearn为优化过的C4 5 这里做一个详细的总结包括 原理 代码 可视化 scikit learn实现 皆为亲自实践后的感悟 以下进入正文 早前简单了解了决策树的原理 然后为