机器学习实战之决策树算法实战详解:sklearn-预测隐形眼镜类型
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了机器学习实战之决策树算法实战详解:sklearn-预测隐形眼镜类型,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含22766字,纯文字阅读大概需要33分钟。
内容图文
我们经常使用决策树处理分类问题,近来的调查表明决策树也是经常使用的数据挖掘算法。
这一系列博客文章都是基于前人的经验,加入一些自己的拙见,仅供参考。
一、决策树构建
1、工作原理
图3-1所示的流程图就是一个决策树,正方形代表判断模块,椭圆形代表终止模块,表示已经得出结论,可以终止运行。从判断模块引出的左右箭头称作分支,它可以到达另一个判断模块或者终止模块。
图3-1构建了一个假想的邮件分类系统,它首先检测发送邮件域名地址。如果地址为myEmployer.com,则将其放在分类“无聊时需要阅读的邮件”中。如果邮件不是来自这个域名,则检查邮件内容是否包含单词曲棍球,如果包含则将邮件归类到“需要及时处理的朋友邮件”,如果不包含则将邮件归类到“无需阅读的垃圾邮件”。
KNN算法可以完成很多分类任务,但是它最大的缺点就是无法给出数据的内在含义,决策树的主要优势就在于数据形式非常容易理解。
决策树很多任务都是为了数据中所蕴含的知识信息,因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则,机器学习算法最终将使用这些机器从数据集中创造的规则。
在构造决策树时,我们需要解决的第一个问题就是,当前数据集上哪个特征在划分数据分类时起决定性作用。 为了找到决定性的特征, 划分出最好的结果,我们必须评估每个特征。完成测试之后,原始数据集就被划分为几个数据子集。这些数据子集会分布在第一个决策点的所有分支上。
如果某个分支下的数据属于同一类型,则当前无需阅读的垃圾邮件已经正确地划分数据分类,无需进一步对数据集进行分割。如果数据子集内的数据不属于同一类型,则需要重复划分数据子集的过程。
如何划分数据子集的算法和划分原始数据集的方法相同,直到所有具有相同类型的数据均在一个数据子集内。
一些决策树算法采用二分法划分数据,本书采用ID3算法划分数据集。
表3-1的数据包含5个海洋生物,特征包括:不浮出水面是否可以生存,以及是否有脚蹼。
我们可以将这些动物分成两类:鱼类 非鱼类。 现在我们想要决定依据第一个特征还是第二个特征划分数据。
在回答这个问题之前吗,我们必须采用量化的方法判断如何划分数据。
2、信息增益
划分数据集的大原则是:将无序的数据变得更加有序。 我们可以使用多种方法划分数据集,但是每种方法都有各自的优缺点。组织杂乱无章数据的一种方法就是使用信息论度量信息,信息论是量化处理信息的分支科学。我们可以在划分数据之前使用信息论量化度量信息的内容。
在划分数据集之前之后信息发生的变化称为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择!
如何计算信息增益?集合信息的度量方式称为香农熵或者简称为熵,这个名字来源于信息论之父克劳德·香农
其中n是分类的数目
熵越大,则随机变量的不确定性越大。
3、计算给定数据集的香农熵
import math
#计算数据集的熵
def calcShannonEnt(dataSet):
#计算数据集中实例的总数
numEntries=len(dataSet)
labelCounts={}
for featVec in dataSet:
currentLabel=featVec[-1]
#如果当前键不存在,则扩展字典并将当前键加入字典
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel]=0
#字典记录下每个键出现的次数(即:当前类别出现的次数)
labelCounts[currentLabel]+=1
#熵
shannonEnt=0.0
for key in labelCounts:
#计算当前键(类别)出现的概率
prob=float(labelCounts[key])/numEntries
#然后用这个概率计算熵,用熵的计算公式
shannonEnt-=prob*math.log(prob,2)
return shannonEnt
def createDataSet():
dataset=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]
labels=['no surfacing','flippers']
return dataset,labels
myDat,labels=createDataSet()
print(myDat)
Ent=calcShannonEnt(myDat)
print(Ent)
#熵越高,则混合的数据也越多,我们可以在数据集中添加更多的分类,观察熵是如何变化的
#将第一个数据的yes改为maybe后,发现新的熵增加了
myDat[0][-1]='maybe'
print(myDat)
newEnt=calcShannonEnt(myDat)
print(newEnt)
得到熵之后,我们就可以按照获取最大信息增益的方法划分数据集
另一个度量集合无序程度的方法是基尼不纯度(Gini impurity),简单地说就是从一个数据集中随机选取子项,度量其被错误分类到其他分组里的概率。(想了解可以百度一下)
4、划分数据集
分类算法除了需要测量信息熵,还需要划分数据集,度量花费数据集的熵,以便判断当前是否正确地划分了数据集,我们将对每个特征划分数据集的结果计算一次信息熵,然后判断按照哪个特征划分数据集是最好的划分方式。
(想象一个分布在二维空间的数据散点图,需要在数据之间画条线,将它们分成两部分,我们应该按照x轴还是y轴划线呢?)
相关语法:
1、list.extend(seq)
extend() 函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。
aList = [123, 'xyz', 'zara', 'abc', 123];
bList = [2009, 'manni'];
aList.extend(bList)
print "Extended List : ", aList ;
Extended List : [123, 'xyz', 'zara', 'abc', 123, 2009, 'manni']
2、list.append(obj)
append() 方法用于在列表末尾添加新的对象。
aList = [123, 'xyz', 'zara', 'abc'];
aList.append( 2009 );
print "Updated List : ", aList;
Updated List : [123, 'xyz', 'zara', 'abc', 2009]
区别在于extend可以一次性增加多个值!而append则是将多个值当成一个值添加!
#按照给定特征划分数据集
#三个输入参数:待划分的数据集、划分数据集的特征、特征的返回值
#返回划分后的数据集
def splitDataSet(dataSet,axis,value):
retDataSet=[]
#遍历数据集中的每个元素,一旦发现符合要求的值,则将其添加到新创建的列表中
for featVec in dataSet:
#if语句中,程序将符合特征的数据抽取出来
print(featVec)
if featVec[axis]==value:
#取开始位置到axis-1的数据
reducedFeatVec=featVec[:axis]
#取axis+1位置到最后的数据添加到reducedFeatVec中
reducedFeatVec.extend(featVec[axis+1:])
#上面两步的目的:去掉axis特征(即去掉axis那一列),因为按照axis特征划分后,数据里面就应该去除axis特征
# 将符合条件的添加到返回的数据集
retDataSet.append(reducedFeatVec)
return retDataSet
# print(splitDataSet(myDat,0,1))
# print(splitDataSet(myDat,0,0))
接下来我们将遍历整个数据集,循环计算香农熵和splitDataSet()函数,找到最好的特征划分方式。
熵计算将会告诉我们如何划分数据集是最好的数据组织方式。
5、计算信息增益实例
一天,老师问了个问题,只根据头发和声音怎么判断一位同学的性别。
为了解决这个问题,同学们马上简单的统计了8位同学的相关特征,数据如下:
同学A打算:先根据头发判断,若判断不出,再根据声音判断
同学B打算:先根据声音判断,然后再根据头发来判断
那么问题来了:同学A和同学B谁的决策树好些?计算机做决策树的时候,面对多个特征,该如何选哪个特征为最佳的划分特征?下面我们就要说一下决策树的特征选择了。
划分数据集的大原则是:将无序的数据变得更加有序。
(无序的数据熵更大,有序的数据熵更小)
一个信息越混乱,则它包含的信息越多,信息量越大!
我们可以使用多种方法划分数据集,但是每种方法都有各自的优缺点。于是我们这么想,如果我们能测量数据的复杂度,对比按不同特征分类后的数据复杂度,若按某一特征分类后复杂度减少的更多,那么这个特征即为最佳分类特征。
我们的目标是:通过一种衡量标准来计算通过不同特征进行分支选择后的分类情况,找出来最好的那个当做根节点,以此类推。而衡量标准就是:熵
在信息论与概率论中,熵(entropy)用于表示“随机变量不确定性的度量”
(解释一下:说白了就是物体内部的混乱程度,比如杂货市场里面什么都有,那肯定乱,而专卖店里面只卖一个牌子,那就稳定了)
1、首先计算未分类前的熵,总共有8位同学,男生3位,女生5位。
熵(总)=-3/8 * log2(3/8)-5/8 * log2(5/8)=0.9544
2、接着分别计算同学A和同学B分类后信息熵。同学A首先按头发分类,分类后的结果为:长头发中有1男3女。短头发中有2男2女。
熵(同学A长发)=-1/4 * log2(1/4)-3/4 * log2(3/4)=0.8113
熵(同学A短发)=-2/4 * log2(2/4)-2/4 * log2(2/4)=1
熵(同学A)=4/8 * 0.8113+4/8 * 1=0.9057
信息增益(同学A)=熵(总)-熵(同学A)=0.9544-0.9057=0.0487
3、同理,按同学B的方法,首先按声音特征来分,分类后的结果为:声音粗中有3男3女。声音细中有0男2女。
熵(同学B声音粗)=-3/6 * log2(3/6)-3/6 * log2(3/6)=1
熵(同学B声音粗)=-2/2 * log2(2/2)=0
熵(同学B)=6/8 * 1+2/8 * 0=0.75
信息增益(同学B)=熵(总)-熵(同学A)=0.9544-0.75=0.2087
综上:按同学B的方法,先按声音特征分类,信息增益更大(即数据变得更有序了),区分样本的能力更强,更具有代表性。
以上就是决策树ID3算法的核心思想。
6、具体实现代码
import math
import operator
#计算信息熵(香农熵),传入整个数据集,但最后只取最后一列(标签)来计算
def calcShannonEnt(dataSet):
#计算数据集中实例的总数
numEntries=len(dataSet)
#保存每个标签(label)出现次数的字典
labelCounts={}
#统计频数,用来计算香农熵
for featVec in dataSet: #对每组特征向量进行统计(featVec中存的是一行一行的特征即其对应的标签:[1,1,'yes'])
currentLabel=featVec[-1] #提取标签(label)信息(每一行的最后一列就是标签(label))
#如果当前标签(label)没有在该字典中,则添加进去
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel]=0
#字典记录下每个标签(label)出现的次数(即:当前标签出现的次数)
labelCounts[currentLabel]+=1
shannonEnt=0.0 #香农熵
for key in labelCounts: #计算香农熵
#计算选择该标签(label)的概率
prob=float(labelCounts[key])/numEntries
#然后用这个概率计算熵,用熵的计算公式
shannonEnt-=prob*math.log(prob,2)
#返回香农熵
return shannonEnt
# def createDataSet():
# dataset=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]
# labels=['no surfacing','flippers']
# return dataset,labels
#
# myDat,labels=createDataSet()
# print(myDat)
# Ent=calcShannonEnt(myDat)
# print(Ent)
#熵越高,则混合的数据也越多,我们可以在数据集中添加更多的分类,观察熵是如何变化的
#将第一个数据的yes改为maybe后,发现新的熵增加了
# myDat[0][-1]='maybe'
# print(myDat)
# newEnt=calcShannonEnt(myDat)
# print(newEnt)
def createDataSet():
dataSet = [[0, 0, 0, 0, 'no'], #数据集
[0, 0, 0, 1, 'no'],
[0, 1, 0, 1, 'yes'],
[0, 1, 1, 0, 'yes'],
[0, 0, 0, 0, 'no'],
[1, 0, 0, 0, 'no'],
[1, 0, 0, 1, 'no'],
[1, 1, 1, 1, 'yes'],
[1, 0, 1, 2, 'yes'],
[1, 0, 1, 2, 'yes'],
[2, 0, 1, 2, 'yes'],
[2, 0, 1, 1, 'yes'],
[2, 1, 0, 1, 'yes'],
[2, 1, 0, 2, 'yes'],
[2, 0, 0, 0, 'no']]
labels = ['年龄', '有工作', '有自己的房子', '信贷情况'] #特征标签
return dataSet, labels #返回数据集和分类属性
#按照给定特征划分数据集
#三个输入参数:待划分的数据集、划分数据集的特征、特征的返回值
#返回划分后的数据集
def splitDataSet(dataSet,axis,value): #axis表示选取第几列特征,value表示某一列特征的具体值(每一行的该特征的值)为多少
retDataSet=[]
#遍历数据集中的每个元素,一旦发现符合要求的值,再进行操作
for featVec in dataSet:
#一行一行数据的遍历
# print(featVec)
#这里只有当值等于传入的value值时,才将数据添加到新的子集中
if featVec[axis]==value:
#取开始位置到axis-1的数据
reducedFeatVec=featVec[:axis]
#取axis+1位置到最后的数据添加到reducedFeatVec中
reducedFeatVec.extend(featVec[axis+1:])
#上面两步的目的:去掉axis特征(即去掉axis那一列)
# 将符合条件的添加到返回的数据集
retDataSet.append(reducedFeatVec)
return retDataSet #这里的子集包含了最后一列标签(label)
#其实,这里没有必要删除axis那一列
#选择最好的数据集划分方式(按照哪个特征划分能使得信息增益最大,信息更有序)
def chooseBestFeatureToSplit(dataSet):
#特征数目,选取第一行来计算(其实哪一行都行),-1是因为每一行的最后一列是类别label
numFeatures=len(dataSet[0])-1
#计算数据集的香农熵(基础的香农熵)
baseEntropy=calcShannonEnt(dataSet)
#最好的信息增益
bestInfoGain=0.0
#最好的特征的索引值(哪一列特征)
bestFeature=-1
#这里外层的for循环是用于遍历每一列的特征
for i in range(numFeatures):
#遍历所有特征(就是除了最后一列标签(label)外,剩下的特征,一列一列的遍历)
#然后计算出每一列特征与最后一列标签的信息增益(infoGain=baseEntropy-newEntropy)
#获取dataSet的第i个所有特征
#for example in dataSet表示,遍历每一行数据,example[i]表示,选择第i列数据,因为i由numFeatures限制,所以一定不会取到标签列(label)
#遍历完之后featList中就存下了第i个特征的所有值
featList=[example[i] for example in dataSet] #以上面的数据为例,当i=0,即为:[1,1,1,0,0]
#转换为set类型,set类型会消除内部重复数据,得到唯一值,即:{1,0}
uniqueVals=set(featList)
#经验条件熵(也就是选择某个特征后的新的香农熵)
newEntropy=0.0
#这里的内层for循环是遍历第i个特征的每个取值,比如第一列特征的取值就有{1,0},用于计算第i个特征的香农熵
for value in uniqueVals:
subDataSet=splitDataSet(dataSet,i,value) #subDataSet划分后的子集
#len计算子集中行的个数(就是有多少数据)
prob=len(subDataSet)/float(len(dataSet)) #计算当前子集的概率
newEntropy+=prob*calcShannonEnt(subDataSet) #根据公式计算新的香农熵
infoGain=baseEntropy-newEntropy #计算信息增益
# print("第%d个特征的增益为%.3f" %(i,infoGain)) #打印每个特征的信息增益
#更新信息增益,找到最大的信息增益
if(infoGain>bestInfoGain):
bestInfoGain=infoGain
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 createTree(dataSet,labels,featLabels):
classList=[example[-1] for example in dataSet] # 取分类标签(label)
if classList.count(classList[0])==len(classList): #如果类别完全相同则停止划分:第一个停止条件
return classList[0]
if len(dataSet[0])==1: #遍历完所有特征时,返回出现次数最多的类标签:第二个停止条件
return majorityCnt(classList) #投票表决法
bestFeat=chooseBestFeatureToSplit(dataSet) #选择最优特征
bestFeatLabel=labels[bestFeat] #最优特征的标签
featLabels.append(bestFeatLabel)
myTree={bestFeatLabel:{}} #根据最优特征的标签生成树
del(labels[bestFeat]) #删除已经使用的特征标签
featValues=[example[bestFeat] for example in dataSet] #得到训练集中所有最优特征的属性值
uniqueVals=set(featValues) #去掉重复的属性值
for value in uniqueVals: #遍历特征,创建决策树
myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),labels,featLabels)
return myTree
#使用决策树的分类函数
def classify(inputTree,featLabels,testVec):
firstStr=inputTree.keys()[0]
secondDict=inputTree[firstStr]
featIndex=featLabels.index(firstStr)
for key in secondDict.keys():
if testVec[featIndex]==key:
if type(secondDict[key]).__name__=='dict':
classLabel=classify(secondDict[key],featLabels,testVec)
else:classLabel=secondDict[key]
return classLabel
if __name__ == '__main__':
dataSet, labels = createDataSet()
featLabels = []
myTree = createTree(dataSet, labels, featLabels)
testVec = [0,1] #测试数据
result = classify(myTree, featLabels, testVec)
if result == 'yes':
print('放贷')
if result == 'no':
print('不放贷')
决策树的存储、可视化部分可以参考:决策树的存储、可视化
二、利用sklearn预测隐形眼镜类型
隐形眼镜数据集是非常著名的数据集,它包含很多换着眼部状态的观察条件以及医生推荐的隐形眼镜类型。隐形眼镜类型包括硬材质(hard)、软材质(soft)以及不适合佩戴隐形眼镜(no lenses)。
数据来源与UCI数据库,数据集下载地址:https://github.com/Jack-Cherish/Machine-Learning/blob/master/Decision%20Tree/classifierStorage.txt
数据预览
一共有24组数据,每一列依次是:age、prescript、astigmatic、tearRate、class
(即:年龄、症状、是否散光、泪流量、分类标签)
young myope no reduced no lenses
young myope no normal soft
young myope yes reduced no lenses
young myope yes normal hard
young hyper no reduced no lenses
young hyper no normal soft
young hyper yes reduced no lenses
young hyper yes normal hard
pre myope no reduced no lenses
pre myope no normal soft
pre myope yes reduced no lenses
pre myope yes normal hard
pre hyper no reduced no lenses
pre hyper no normal soft
pre hyper yes reduced no lenses
pre hyper yes normal no lenses
presbyopic myope no reduced no lenses
presbyopic myope no normal no lenses
presbyopic myope yes reduced no lenses
presbyopic myope yes normal hard
presbyopic hyper no reduced no lenses
presbyopic hyper no normal soft
presbyopic hyper yes reduced no lenses
presbyopic hyper yes normal no lenses
可以利用上面自己构造的决策树,也可以使用sklearn实现,这里我们用sklearn。
sklearn.tree.DecisionTreeClassifier()
参数说明如下:
-
criterion: 特征选择标准,可选参数,默认是gini,可以设置为entropy。gini是基尼不纯度,是将来自集合的某种结果随机应用于某一数据项的预期误差率,是一种基于统计的思想。entropy是香农熵,也就是上篇文章讲过的内容,是一种基于信息论的思想。ID3算法使用的是entropy,CART算法使用的则是gini。(上面的内容是以ID3算法为例)
-
splitter: 特征划分点选择标准,可选参数,默认是best,可以设置为random。每个结点的选择策略。best参数是根据算法选择最佳的切分特征,例如gini、entropy。
random随机地在部分划分点中找局部最优的划分点。 默认的”best”适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐”random”。 -
max_features: 划分时考虑的最大特征数,可选参数,默认是None。 寻找最佳切分时考虑的最大特征数(n_features为总共的特征数),有如下6种情况:
- 如果max_features是整型的数,则考虑max_features个特征;
- 如果max_features是浮点型的数,则考虑int(max_features * n_features)个特征;
- 如果max_features设为auto,那么max_features = sqrt(n_features);
- 如果max_features设为sqrt,那么max_featrues = sqrt(n_features),跟auto一样;
- 如果max_features设为log2,那么max_features = log2(n_features);
- 如果max_features设为None,那么max_features = n_features,也就是所有特征都用。
- 一般来说,如果样本特征数不多,比如小于50,我们用默认的”None”就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
-
max_depth: 决策树最大深,可选参数,默认是None。这个参数是这是树的层数的。 层数的概念就是,比如在贷款的例子中,决策树的层数是2层。如果这个参数设置为None,那么决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。或者如果设置了min_samples_slipt参数,那么直到少于min_smaples_split个样本为止。 如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
-
min_samples_split: 内部节点再划分所需最小样本数,可选参数,默认是2。 这个值限制了子树继续划分的条件。 如果min_samples_split为整数,那么在切分内部结点的时候,min_samples_split作为最小的样本数,也就是说,如果样本已经少于min_samples_split个样本,则停止继续切分。 如果min_samples_split为浮点数,那么min_samples_split就是一个百分比,ceil(min_samples_split * n_samples),数是向上取整的。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
-
min_weight_fraction_leaf: 叶子节点最小的样本权重和,可选参数,默认是0。 这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
-
max_leaf_nodes: 最大叶子节点数,可选参数,默认是None。通过限制最大叶子节点数,可以防止过拟合。 如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
-
class_weight: 类别权重,可选参数,默认是None,也可以字典、字典列表、balanced。指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。 类别的权重可以通过{class_label:weight}这样的格式给出,这里可以自己指定各个样本的权重,或者用balanced,如果使用balanced,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的None。
-
random_state: 可选参数,默认是None。随机数种子。 如果是证书,那么random_state会作为随机数生成器的随机数种子。随机数种子,如果没有设置随机数,随机出来的数与当前系统时间有关,每个时刻都是不同的。如果设置了随机数种子,那么相同随机数种子,不同时刻产生的随机数也是相同的。如果是RandomState instance,那么random_state是随机数生成器。如果为None,则随机数生成器使用np.random。
-
min_impurity_split: 节点划分最小不纯度,可选参数,默认是1e-7。 这是个阈值,这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。
-
presort: 数据是否预排序,可选参数,默认为False,这个值是布尔值,默认是False不排序。 一般来说,如果样本量少或者限制了一个深度很小的决策树,设置为true可以让划分点选择更加快,决策树建立的更加快。如果样本量太大的话,反而没有什么好处。问题是样本量少的时候,我速度本来就不慢。所以这个值一般懒得理它就可以了。
调参时的注意点
- 当样本数量少但是样本特征非常多的时候,决策树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型
- 如果样本数量少但是样本特征非常多,在拟合决策树模型前,推荐先做维度规约,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA)。这样特征的维度会大大减小。再来拟合决策树模型效果会好。
- 推荐多用决策树的可视化,同时先限制决策树的深度,这样可以先观察下生成的决策树里数据的初步拟合情况,然后再决定是否要增加深度。
- 在训练模型时,注意观察样本的类别情况(主要指分类树),如果类别分布非常不均匀,就要考虑用class_weight来限制模型过于偏向样本多的类别。
- 决策树的数组使用的是numpy的float32类型,如果训练数据不是这样的格式,算法会先做copy再运行。
- 如果输入的样本矩阵是稀疏的,推荐在拟合前调用csc_matrix稀疏化,在预测前调用csr_matrix稀疏化。
sklearn.tree.DecisionTreeClassifier()提供了一些方法供我们使用,如下图所示:
接下来开始编写代码:
注意:fit()函数,不能接收string类型的数据,要转换为int型才行。
fit()函数参数:
我们需要对数据集进行编码,这里有两种方法:
- LabelEncoder:将字符串转换为增量值(0、1、2、3)
- OneHotEncoder:使用One-of-K算法将字符串转换为整数
导入:
from sklearn.preprocessing import LabelEncoder
最终代码:
import pandas as pd
from sklearn import tree
from sklearn.preprocessing import LabelEncoder
from six import StringIO
import pydotplus
if __name__=='__main__':
#导入数据
data=pd.read_csv(r'B:\电子书\机器学习实战+源码\machinelearninginaction\Ch03\lenses.txt',
sep='\t',names=['age','prescript','astigmatic','tearRate','lenses'])
# print(data.head())
labelData=pd.DataFrame(data,columns=['lenses'])
# print(labelData.head())
newData=pd.DataFrame(data,columns=['age','prescript','astigmatic','tearRate'])
# print(newData)
# print(newData.values)
# print(newData.values.tolist())
# print(newData.head())
#数据序列化,以便传入fit()函数
for col in newData.columns:
print(newData[col])
newData[col]=LabelEncoder().fit_transform(newData[col]) #注意!LabelEncoder()后面有括号!!
print(newData.head())
#使用Graphviz可视化决策树
#创建DecisionTreeClassifier()类
clf=tree.DecisionTreeClassifier(max_depth=4)
clf=clf.fit(newData.values,labelData) #使用数据,构建决策树
dot_data=StringIO()
tree.export_graphviz(clf,out_file=dot_data,
feature_names=newData.keys(),
class_names=clf.classes_,
filled=True,rounded=True,
special_characters=True)
graph=pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf("tree.pdf") #保存绘制好的决策树,以PDF的形式存储
#进行预测
#注意:传入的数据也必须是int型,需要在读取数据的时候帮用户进行处理
print(clf.predict([[1, 1, 1, 0]])) # 预测
决策树可视化:
三、总结
采用sklearn实现决策树,只需要知道每个函数的参数和用途,做好数据预处理,就可以快速实现决策树的构建。(慢慢地成为了一名“调参侠”)
决策树的一些优点:
- 易于理解和解释,决策树可以可视化。
- 几乎不需要数据预处理。其他方法经常需要数据标准化,创建虚拟变量和删除缺失值。决策树还不支持缺失值。
- 使用树的花费(例如预测数据)是训练数据点(data points)数量的对数。
- 可以同时处理数值变量和分类变量。其他方法大都适用于分析一种变量的集合。
- 可以处理多值输出变量问题。
- 使用白盒模型。如果一个情况被观察到,使用逻辑判断容易表示这种规则。相反,如果是黑盒模型(例如人工神经网络),结果会非常难解释。
- 即使对真实模型来说,假设无效的情况下,也可以较好的适用。
决策树的一些缺点:
- 决策树学习可能创建一个过于复杂的树,并不能很好的预测数据。也就是过拟合。修剪机制(现在不支持),设置一个叶子节点需要的最小样本数量,或者数的最大深度,可以避免过拟合。
- 决策树可能是不稳定的,因为即使非常小的变异,可能会产生一颗完全不同的树。这个问题通过decision trees with an ensemble来缓解。
- 学习一颗最优的决策树是一个NP-完全问题under several aspects of optimality and even for simple concepts。因此,传统决策树算法基于启发式算法,例如贪婪算法,即每个节点创建最优决策。这些算法不能产生一个全家最优的决策树。对样本和特征随机抽样可以降低整体效果偏差。
- 概念难以学习,因为决策树没有很好的解释他们,例如,XOR, parity or multiplexer problems.
- 如果某些分类占优势,决策树将会创建一棵有偏差的树。因此,建议在训练之前,先抽样使样本均衡。
补充:
决策树ID3算法、C4.5算法讲解
决策树CART分类算法讲解
内容总结
以上是互联网集市为您收集整理的机器学习实战之决策树算法实战详解:sklearn-预测隐形眼镜类型全部内容,希望文章能够帮你解决机器学习实战之决策树算法实战详解:sklearn-预测隐形眼镜类型所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。