3.1.1
>>>a="qwe"
>>> a[-1]
'e'
列表的最后一位是-1.
>>>import trees
之后在Python的console中就可以使用trees.py中的函数了。
>>> lc={}
>>>lc["no"]=0
>>>lc['yes']=3
>>> lc
{'yes': 3, 'no':0}
>>>lc.keys()
['yes', 'no']
>>>lc.values()
[3, 0]
一个简单的例子,字典lc由key和value组成。这里,key是'no'和'yes',value分别是0和3。
>>> 'yes'in lc.keys()
True
>>> 'mo'in lc.keys()
False
可以用keys()函数检测字典中有什么样的key。
>>>float(lc['no'])
0.0
>>>float(lc['yes'])
3.0
根据 key得到相应的value,并且将value转化成float形式。
>>>mydata
[[1, 1, 'yes'],[1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>>trees.calcShannonEnt(mydata)
0.9709505944546686
在这个函数中会新建一个字典labelCounts = {},输入mydata经过计算后,该字典中的key是’'yes'和'no',相应的value是2和3.求出每种key发生的频率,求对数后,可以得到相应的熵。
3.1.2
>>>a=[0,1,2,3,4,5]
>>>b=a[:2]
>>> b
[0, 1]
b包含的列表的前面两个数。
>>>c=a[3:]
>>> c
[3, 4, 5]
c包含了列表的从第3个数开始到最后一个数(开头的是第0个数)。
>>>b.extend(c)
>>> b
[0, 1, 3, 4, 5]
把c中的元素加到b中,b比a少了第2个数。
>>>d=b.extend(c)
>>> d
错误用法,d显示为空。
>>>b.append(c)
>>> b
[0, 1, 3, 4, 5,[3, 4, 5]]
跟上面对比可以看出,extend是把列表中的元素一个个加进去,append是将列表整个加进去。
>>>mydata
[[1, 1, 'yes'],[1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
>>>d=[a[0] for a in mydata]
>>> d
[1, 1, 1, 0, 0]
>>>set(d)
set([0, 1])
>>>e=set(d)
>>> e
set([0, 1])
>>> y=[ vfor v in e]
>>> y
[0, 1]
可以用这些函数将mydata中5条数据中的第0个元素提取出来,然后看第0个元素有多少种类,组成一个集合。
>>>trees.chooseBestFeatureToSplit(mydata)
0
这个函数先将mydata根据每条数据中的第0个元素的分类(第0个元素是1)形成一个新的子集[[1, 'yes'], [1, 'yes'], [ 0, 'no']],根据'yes'和'no'计算该子集的熵,乘以3/5的比例后加到newEntropy中,然后再根据第0个元素的分类(第0个元素是0)形成一个新的子集[ [1, 'no'], [1, 'no']], 根据'yes'和'no'计算该子集的熵,乘以2/5的比例后加到newEntropy中。同样原理可以将mydata根据每条数据中的第1个元素的分类得到相应的newEntropy。该函数等效于比较newEntropy的大小,根据第i个元素得到的newEntropy小,就把bestFeature改成i。
3.13
>>>mytree=trees.createTree(mydata,label)
>>>mytree
{'no surfacing':{0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
这个函数的输入是mydata和label,返回的是包含了很多代表树结构信息的嵌套字典。当进入函数,但还没有进入 for value in uniqueVals:循环前,mytree={'no surfacing': {}}。 uniqueVals是一个有0和1的set,由数据集中的第0个元素得到。
>>>mytree['no surfacing']
{}
mytree['nosurfacing']是一个空的字典
mytree['nosurfacing'][0]
这相当于在空字典中新建一个名称为0的key,而创建与该key对应的value则需要再一次进入 createTree()函数。这次输入的数据集是:[[1, 'no'], [1, 'no']]
>>>trees.splitDataSet(mydata,0,0)
[[1, 'no'], [1,'no']]
由于输入数据集的两个数据最后一个元素类别完全相同,都是'no',所以,直接返回'no'。这时mytree={'no surfacing': {0: 'no'}}。
然后运行mytree['no surfacing'][1],相当于在嵌套的字典中再新建一个名称为1的key,与前面那个名称为0的key并列。而创建与该key对应的value则需要再一次进入 createTree()函数。这次输入的数据集是:[[1, 'yes'], [1, 'yes'], [0, 'no']]
>>>trees.splitDataSet(mydata,0,1)
[[1, 'yes'], [1,'yes'], [0, 'no']]
接下来又会新建一个字典,假设是 mytree2={'flippers': {}}。
然后进入for value in uniqueVals:循环, uniqueVals是一个有0和1的set,由数据集中的第1个元素得到。在空字典中新建一个名称为0的key,而创建与该key对应的value则需要再一次进入 createTree()函数。这次输入的数据集是:[['no']]
>>>b=trees.splitDataSet(mydata,0,1)
>>> b
[[1, 'yes'], [1,'yes'], [0, 'no']]
>>>trees.splitDataSet(b,0,0)
[['no']]
所以返回的是'no'。这时mytree2={'flippers': {0:'no'}}
接下去在字典中新建一个名称为1的key,而创建与该key对应的value则需要再一次进入 createTree()函数。这次输入的数据集是:[['yes'], ['yes']]
>>>trees.splitDataSet(b,0,1)
[['yes'], ['yes']]
所以返回的是'yes'。这时mytree2={'flippers': {0: 'no', 1: 'yes'}}.
跳出for value in uniqueVals:循环,返还mytree2。这时mytree={'no surfacing': {0: 'no', 1: {'flippers':{0: 'no', 1: 'yes'}}}}
最后跳出前面一个for value in uniqueVals:循环,返还mytree。
3.2.1
Linux系统中没有自己安装matplotlib。所以要在linux命令行中输入:
sudo apt-getinstall python-matplotlib
>>>dict(p='pig',d='dog')
{'p': 'pig', 'd':'dog'}
>>>dict(p="pig",d="dog")
dict函数用于构造字典,双引号和单引号效果一样。
在官方给的例程中有两个createPlot(),但是把3.2.1中的createPlot()函数用#号屏蔽掉了,把多个#号删除,并且把那个createPlot()改成createPlot2()。输入下面命令:
>>>reload(treePlotter)
<module'treePlotter' from 'treePlotter.py'>
>>>treePlotter.createPlot2()
可以得到书中图3-5的图像。
plotNode()函数中nodeTxt指的是要在图中打印的文字,xy是箭头起始的座标,xytext是文字的位置。axes fraction指的是座标的值是从0到1的。arrowstyle="<-"指的是箭头是指向文字的,bbox是包装文字的盒子,有圆润的和锯齿形两种。
createPlot()函数中的createPlot.ax1是全局变量,所以该函数中调用的plotNode函数也可以对createPlot.ax1进行修改。
getNumLeafs()函数中myTree.keys()[0]指的是myTree字典中第0个key,也就是'no surfacing'。secondDict是{0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}。然后进入循环for key in secondDict.keys():。secondDict里面有两个key,当key等于0时,所对应的secondDict[key]不是字典,所以进入else语句,此时numLeafs==1。当key==1时,所对应的secondDict[key]不是字典,所以又进入getNumLeafs函数中(为了与前面的区分,假设为getNumLeafs2),输入的字典为{'flippers': {0: 'no', 1: 'yes'}},输入字典的value中没有字典了,返还numLeafs(为了与前面的区分,假设为NumLeafs2),numLeafs2=2。跳出getNumLeafs2函数,此时numLeafs==3,返还numLeafs,跳出getNumLeafs函数。
getTreeDepth()函数与前面一个函数大致一样,不一样的是在if type(secondDict[key]).__name__=='dict':语句后thisDepth至少是1,如果不是字典,那么thisDepth就是1。
plotTree()函数的输入是myTree,parentPt,nodeText。当createPlot函数调用该函数时,myTree=={'no surfacing': {0: 'no', 1: {'flippers': {0:'no', 1: 'yes'}}}},parentPt==(0.5,1.0),nodeText==‘ ’。进入函数后firstStr='no surfacing',plotTree()函数中的cntrPt是用来计算当前决策节点的位置。假设现在的 plotTree.xOff记为x(也就是上一个叶节点的x轴位置),总的叶节点plotTree.totalW为N,输入myTree的叶节点numLeafs为n。那么当前决策节点下面的叶节点x轴就是(x+1/N, x+2/N.............x+n/N),那么决策节点的x轴位置应该是 x+1/N和 x+n/N的中间,也就是[2x+(1+n)/N]/2,y轴位置不变。cntrPt==(0.5,1.0),接下来的两个函数plotNode()和plotMidText()就画了一个位于(0.5,1)的决策节点。接下来plotTree.yOff=0.5。secondDict=={0: 'no', 1: {'flippers': {0: 'no', 1:'yes'}}}。接下去的for循环。首先key==0,进入else语句,plotTree.xOff变成了0.5/3,于是plotNode()在(plotTree.xOff,plotTree.yOff)即(0.5/3,0.5)画了一个no的叶节点,plotMidText()在cntrPt和(plotTree.xOff,plotTree.yOff)中间写上key的名称0。接着key==1,进入if语句,进入循环(假设是plotTree2()),输入是myTree== {'flippers': {0: 'no', 1: 'yes'}},parentPt==(0.5,1.0),nodeText==‘ 1’。接下来,cntrPt变成了(2/3,0.5),然后从 parentPt到cntrPt画了一个箭头到决策节点,中间标上 nodeText,secondDict 变成{0: 'no', 1: 'yes'},plotTree.yOff变成0。接下来进入for循环,由于 secondDict中没有字典,所以循环的两次都有进入else语句。当key==0时,从cntrPt到(plotTree.xOff,plotTree.yOff)==(1.5/3,0)处画箭头到叶节点,中间表上str(key)。当key==1时,从cntrPt到(plotTree.xOff,plotTree.yOff)==(2.5/3,0)处画箭头到叶节点,中间表上str(key)。跳出plotTree2(),接着再跳出plotTree()。
3.4
>>>ar=open('lenses.txt')
>>>a=ar.readlines()
>>> a
['young\tmyope\tno\treduced\tnolenses\r\n', 'young\tmyope\tno\tnormal\tsoft\r\n','young\tmyope\tyes\treduced\tno lenses\r\n', 'young\tmyope\tyes\tnormal\thard\r\n','young\thyper\tno\treduced\tno lenses\r\n','young\thyper\tno\tnormal\tsoft\r\n', 'young\thyper\tyes\treduced\tnolenses\r\n', 'young\thyper\tyes\tnormal\thard\r\n','pre\tmyope\tno\treduced\tno lenses\r\n', 'pre\tmyope\tno\tnormal\tsoft\r\n','pre\tmyope\tyes\treduced\tno lenses\r\n', 'pre\tmyope\tyes\tnormal\thard\r\n','pre\thyper\tno\treduced\tno lenses\r\n', 'pre\thyper\tno\tnormal\tsoft\r\n','pre\thyper\tyes\treduced\tno lenses\r\n', 'pre\thyper\tyes\tnormal\tnolenses\r\n', 'presbyopic\tmyope\tno\treduced\tno lenses\r\n','presbyopic\tmyope\tno\tnormal\tno lenses\r\n','presbyopic\tmyope\tyes\treduced\tno lenses\r\n','presbyopic\tmyope\tyes\tnormal\thard\r\n', 'presbyopic\thyper\tno\treduced\tnolenses\r\n', 'presbyopic\thyper\tno\tnormal\tsoft\r\n','presbyopic\thyper\tyes\treduced\tno lenses\r\n','presbyopic\thyper\tyes\tnormal\tno lenses\r\n']
>>> a[0]
'young\tmyope\tno\treduced\tnolenses\r\n'
>>>a[0].strip()
'young\tmyope\tno\treduced\tnolenses'
>>>a[0].strip().split('\t')
['young', 'myope','no', 'reduced', 'no lenses']
>>>fr=open('lenses.txt')
>>> fr
<open file'lenses.txt', mode 'r' at 0x7f5600bf6660>
>>>lenses=[inst.strip().split('\t') for inst in fr.readlines()]
>>>lenses
[['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']]
>>>lensesTree=trees.createTree(lenses,lensesLabels)
>>>treePlotter.createPlot(lensesTree)