《机器学习实战》斧头书——第三章—决策树(1)——使用决策树预测你是否需要带隐形眼镜

《机器学习实战》斧头书——决策树

一、对文章的说明

1.1 对本文有几点说明如下:

1.1.1 我是一个刚学没多久的小白,所以代码可能也会有错误,欢迎各位大佬提出我的问题,感谢;
1.1.2 对于python版本 ,斧头书《机器学习实战》是用的2.x,本文使用的是3.x,然后代码的话,有的是参考书上的和网上的,还有部分是自己写的;
1.1.3 用的参考书是下面这本,封面拿了个斧头的人,这本书没有调库,都是用python写的底层代码,感觉对理解算法原理会更深入一点;
1.1.4 编写代码的地方,先是在Jupyter notebook上编写和部分代码的测试,最后在PyCharm上集成和封装。

二、项目背景

2.1 背景1

本节我们将通过一个例子讲解决策树如何预测患者需要佩戴的隐形眼镜类型。使用小数据集,我们就可以利用决策树学到很多知识:眼科医生是如何判断患者需要佩戴的镜片类型;一旦理解了决策树的工作原理,我们甚至也可以帮助人们判断需要佩戴的镜片类型。

2.2 背景2

隐形眼镜数据集是非常著名的数据集,它包含很多患者眼部状况的观察条件以及医生推荐的隐形眼镜类型。隐形眼镜类型包括硬材质、软材质以及不适合佩戴隐形眼镜。

2.3 熵的计算公式

先是信息的定义:
在这里插入图片描述
再是熵,熵就是信息的期望值(期望值就是平均值):
在这里插入图片描述

三、代码

3.1 隐形眼镜的数据集

astigmatic是散光的意思;myope是近视眼,hyper是更加近视,最后labels是根据前面的条件判断你是“不需要带隐形眼镜”还是“带软的”还是“带硬的”。

    age	 	 prescript	astigmatic	tearRate	labels
0	young		myope	no			reduced		no lenses
1	young		myope	no			normal		soft
2	young		myope	yes			reduced		no lenses
3	young		myope	yes			normal		hard
4	young		hyper	no			reduced		no lenses
5	young		hyper	no			normal		soft
6	young		hyper	yes			reduced		no lenses
7	young		hyper	yes			normal		hard
8	pre			myope	no			reduced		no lenses
9	pre			myope	no			normal		soft
10	pre			myope	yes			reduced		no lenses
11	pre			myope	yes			normal		hard
12	pre			hyper	no			reduced		no lenses
13	pre			hyper	no			normal		soft
14	pre			hyper	yes			reduced		no lenses
15	pre			hyper	yes			normal		no lenses
16	presbyopic	myope	no			reduced		no lenses
17	presbyopic	myope	no			normal		no lenses
18	presbyopic	myope	yes			reduced		no lenses
19	presbyopic	myope	yes			normal		hard
20	presbyopic	hyper	no			reduced		no lenses
21	presbyopic	hyper	no			normal		soft
22	presbyopic	hyper	yes			reduced		no lenses
23	presbyopic	hyper	yes			normal		no lenses
#将标称型数据  转换成  数值型,否则无法用sklearn库画图。
age	prescript	astigmatic	tearRate
0	0	0	0	0
1	0	0	0	1
2	0	0	1	0
3	0	0	1	1
4	0	1	0	0
5	0	1	0	1
6	0	1	1	0
7	0	1	1	1
8	1	0	0	0
9	1	0	0	1
10	1	0	1	0
11	1	0	1	1
12	1	1	0	0
13	1	1	0	1
14	1	1	1	0
15	1	1	1	1
16	2	0	0	0
17	2	0	0	1
18	2	0	1	0
19	2	0	1	1
20	2	1	0	0
21	2	1	0	1
22	2	1	1	0
23	2	1	1	1

这是数值型的labels
在这里插入图片描述

3.2 先是计算熵增部分的代码(根据公式编程)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#创建数据集  
dataSet = pd.read_csv('lenses.txt',sep='\t',names=['age','prescript','astigmatic','tearRate','labels'])
#从当前文件夹读取数据
#这里数据的分隔符sep是Tab,即\t。添加列名names
def calEnt(dataSet): #计算信息熵的函数
    n = dataSet.shape[0] #数据集总行数
    iset = dataSet.iloc[:,-1].value_counts() #标签的所有类别
    p = iset/n #每一类标签所占比
    ent = (-p*np.log2(p)).sum() #计算信息熵
    return ent
def bestSplit(dataSet):#选择最优的列进行切分的函数
    baseEnt = calEnt(dataSet) #计算原始熵
    bestGain = 0 #初始化信息增益
    axis = -1 #初始化最佳切分列,标签列
    for i in range(dataSet.shape[1]-1): #对特征的每一列进行循环   1和0
        levels= dataSet.iloc[:,i].value_counts().index #提取出当前列的所有取值
        ents = 0 #初始化子节点的信息熵
        for j in levels: #对当前列的每一个取值进行循环    j=1和0
            childSet = dataSet[dataSet.iloc[:,i]==j] #某一个子节点的dataframe
            # print("childSet:\n",childSet)
            ent = calEnt(childSet) #计算某一个子节点的信息熵
            ents += (childSet.shape[0]/dataSet.shape[0])*ent #计算当前列的信息熵
            # print(f'第{i}列的信息熵为{ents}')
        infoGain = baseEnt-ents #计算当前列的信息增益
        # print(f'第{i}列的信息增益为{infoGain}')
        if (infoGain > bestGain):
            bestGain = infoGain #选择最大信息增益
            axis = i #最大信息增益所在列的索引
    return axis
def mySplit(dataSet,axis,value): #选择某一列和某一值进行分割
    col = dataSet.columns[axis]
    rest_dataSet = dataSet.loc[dataSet[col]==value,:].drop(col,axis=1)
    return rest_dataSet
def createTree(dataSet): #创建决策树的函数
    featlist = list(dataSet.columns) #提取出数据集所有的列
    classlist = dataSet.iloc[:,-1].value_counts() #获取最后一列类标签
    #最多标签数目是否等于数据集行数,或者数据集是否只有一列的时候就直接返回
    if classlist[0]==dataSet.shape[0] or dataSet.shape[1] == 1:
        return classlist.index[0] #如果是,返回类标签
    axis = bestSplit(dataSet) #确定出当前最佳切分列的索引
    bestfeat = featlist[axis] #获取该索引对应的特征
    myTree = {bestfeat:{}} #采用字典嵌套的方式存储树信息
    del featlist[axis] #删除当前特征,因为用完了下次就不会再用了
    valuelist = set(dataSet.iloc[:,axis]) #提取最佳切分列所有属性值
    for value in valuelist: #对每一个属性值递归建树
        myTree[bestfeat][value] = createTree(mySplit(dataSet,axis,value))
    return myTree
myTree_lenses = createTree(dataSet)
#把决策树存储起来
np.save('myTree_lenses.npy',myTree_lenses)
#决策树的读取  不加.item()的话,输出的是array格式,加了就提取里面的内容了。allow_pickle=True要加,不然会报错。
read_myTree_lenses = np.load('myTree_lenses.npy',allow_pickle=True).item()
def classify(inputTree,labels,testVec):
    firstStr = next(iter(inputTree)) #获取决策树第一个节点
    secondDict = inputTree[firstStr] #下一个字典
    featIndex = labels.index(firstStr) #第一个节点所在列的索引
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]) == dict :
                classLabel = classify(secondDict[key], labels, testVec)
            else:
                classLabel = secondDict[key]
    return classLabel
labels = list(dataSet.columns)#获取标签值
def acc_classify(train,test):
    inputTree = createTree(train) #根据测试集生成一棵树
    labels = list(train.columns) #数据集所有的列名称
    result = []
    for i in range(test.shape[0]): #对测试集中每一条数据进行循环
        testVec = test.iloc[i,:-1] #测试集中的一个实例
        classLabel = classify(inputTree,labels,testVec) #预测该实例的分类
        result.append(classLabel) #将分类结果追加到result列表中
    test1=test.copy()# 不加会有警告,好像不能直接加1列
    test1['predict']=result #将预测结果追加到测试集最后一列
    acc = (test1.iloc[:,-1]==test1.iloc[:,-2]).mean() #计算准确率
    print(f'模型预测准确率为{acc}')
    return test1
train = dataSet
test = dataSet.iloc[:3,:]
acc_classify(train,test)

3.3 看一下结果—准确率

模型预测准确率为1.0,但是画树实在是有点复杂,接下来在Jupyter notebook上用sklearn库来实现决策树的图的绘制。
在这里插入图片描述

3.4 再是画图部分的代码

#导入相应的包
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
import graphviz
#先创建1个空的DataFrame
empty = pd.DataFrame(columns={'age':'','prescript':'','astigmatic':'','tearRate':''},index=range(24))
#将 Xtrain的所有  标称值 转换为 数值型
#不然它无法判断,它是自己根据数据的大小来选定一个中间值进行划分的
xlabel = ['age','prescript','astigmatic','tearRate'] # 4个特征
Xtrain = pd.DataFrame(columns={'age':'','prescript':'','astigmatic':'','tearRate':''},index=range(24)) #先创建一个空的dataframe,大小为24行,4列。方便后面加入转换好的数据。
for i in range(4): #0 1 2 3
    Xtrain1 = dataSet.iloc[:,i]
    labels = Xtrain1.unique().tolist()
    Xtrain1 = Xtrain1.apply(lambda x: labels.index(x)) #将本文转换为数字
    Xtrain[xlabel[i]]=Xtrain1 #对应的列  加入对应转换好的数值
#标签
Ytrain = dataSet.iloc[:,-1]
labels = Ytrain.unique().tolist()
Ytrain = Ytrain.apply(lambda x: labels.index(x)) #将本文转换为数字

#这是绘制 简单的 没颜色的 方的 树模型
clf = DecisionTreeClassifier()
clf = clf.fit(Xtrain, Ytrain)
tree.export_graphviz(clf)

#给图形增加标签和颜色,而且换成了圆形的框
dot_data = tree.export_graphviz(clf, out_file=None,
                                feature_names=['age','prescript','astigmatic','tearRate'],
                                class_names=['no lenses', 'soft','hard'],
                                filled=True, rounded=True,
                                special_characters=True)
graphviz.Source(dot_data)

3.5 话不多说,上图。

先是普通版:
在这里插入图片描述
再是VIP版决策树的图:(分支都是左边Ture,右边False)
在这里插入图片描述

四、总结

4.1 决策树有点分类得太好了,就是过拟合了,因为那个预测都100%了,其实还需要剪枝,这个在第九章树回归了。
4.2 sep=’\t’可以用于Tab分隔符的数据。
4.3 决策树的构造算法有很多很多,最流行的是C4.5和CART,不同算法的分类依据也不同,这里用的是信息增益,信息增益越大的,熵减小的速度就越快,本书第9章讨论回归问题时将介绍CART算法,CART用的就是基尼不纯度了,越小越好,gini=0的就是最纯的。
4.4 熵,以前高中化学讲过,其实就是表示混乱程度用的,熵越大,越混乱,熵越小,越纯净,没杂质。
4.5 多写几个子函数,更方便点。
4.6 决策树模型生成后一定要及时保存,不然下一次再生成,如果数据多的话,会很浪费时间的。下次要用就直接load就行了。
4.7 其实一开始是在Jupyter notebook上写的,那个方便看结果,全部写好后,再去pycharm上封装起来,方便以后的使用。
4.8 两种方法: 用列表和字典创建空数据框
df = pd.DataFrame(data=None,columns=range(0,3),index=[0,1,2])
在这里插入图片描述

或者
df = pd.DataFrame(columns={‘qqq’:"",‘www’:""},index=[0,1])
在这里插入图片描述
4.9 谢谢阅读,我是刚学不久的小白,有错误的话欢迎各位大佬提出来,共同进步,谢谢了。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树算法是一种广泛应用于分类和回归的机器学习算法,它基于树形结构对样本进行分类或预测决策树算法的主要思想是通过一系列的判断来对样本进行分类或预测。在决策树中,每个节点表示一个属性或特征,每个分支代表该属性或特征的一个取值,而每个叶子节点代表一个分类或预测结果。 决策树算法的训练过程主要包括以下步骤: 1. 特征选择:根据某种指标(如信息增益或基尼系数)选择最优的特征作为当前节点的分裂属性。 2. 决策树生成:根据选择的特征将数据集分成若干个子集,并递归地生成决策树。 3. 剪枝:通过剪枝操作来提高决策树的泛化性能。 决策树算法的优点包括易于理解和解释、计算复杂度较低、对缺失值不敏感等。但是,决策树算法也存在一些缺点,如容易出现过拟合、对离散数据敏感等。 下面是一个决策树算法的案例:假设我们要根据一个人的年龄、性别、教育程度和职业预测其收入水平(高于或低于50K)。首先,我们需要将这些特征进行编码,将其转换为数值型数据。然后,我们可以使用决策树算法对这些数据进行训练,并生成一个决策树模型。最后,我们可以使用该模型对新的数据进行分类或预测。例如,根据一个人的年龄、性别、教育程度和职业,我们可以使用决策树模型预测该人的收入水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值