一、Python实现决策树
我们看一组实例,贷款申请样本数据表。
希望通过所给的训练数据学习一个贷款申请的决策树,用以对未来的贷款申请进行分类,即当新的客户提出贷款申请时,根据申请人的特征利用决策树决定是否批准贷款申请。
在编写代码之前,我们先对数据集进行属性标注。
- 年龄:0代表青年,1代表中年,2代表老年;
- 有工作:0代表否,1代表是;
- 有自己的房子:0代表否,1代表是;
- 信贷情况:0代表一般,1代表好,2代表非常好;
- 类别(是否给贷款):no代表否,yes代表是。
确定这些之后,我们就可以创建数据集,并计算经验熵了,代码编写如下:
# -*- coding: UTF-8 -*-
from math import log
'''
程序来源:https://zhuanlan.zhihu.com/p/28688281,决策树用于决定是否放贷。
'''
def createDataSet():
'''
1)在Python当中定义一个函数,以一个冒号开始,并且缩进
2)在Python当中,return [表达式] 结束函数,选择性地返回一个值给调用方。
不带表达式的return相当于返回 None。
'''
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']
]
'''
python中的中括号[ ]:代表list列表数据类型,列表是一种可变的序列。
'''
labels = ['不放贷', '放贷'] #分类属性
return dataSet, labels #返回数据集和分类属性
'''
python返回多值
python函数可以返回多个值吗?答案是肯定的。
比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的坐标:
# math包提供了sin()和 cos()函数,我们先用import引用它:
import math
def move(x, y, step, angle):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
print(move(100, 100, 60, math.pi / 6))
'''
def calcShannonEnt(dataSet):
numEntires = len(dataSet) #返回数据集的个数(15),return the number of items of a sequence or collection.
labelCounts = {} #保存每个标签(Label)出现次数的字典
'''
python当中“{}”表示字典,具体用法如下
字典写法:d={'a':1,'b':2}
基本字典操作方法:
(1)求元素个数:len(d) => 2
(2)用键访问值:d['a'] => 1
(3)修改值:d['a']=3
(4)删除: del d['a']
(5)成员资格: 'a' in d
'''
for featVec in dataSet: #对每组特征向量进行统计
currentLabel = featVec[-1] #提取标签(Label)信息
'''
python当中“[]”表示索引
arr[-1]表示数组(序列)的最后一个元素,这样第一次执行的时候currentLable就取最后一个元素“no”,然后执行下面的if语句,再第二次执行for语句...
'''
if currentLabel not in labelCounts.keys(): #如果标签(Label)没有放入统计次数的字典,添加进去,开始执行的时候,由于容器是空的,因此第一遍labelCounts['no']是满足if语句的,因此会执行后面的语句,此时labelCounts['no']=0,再次执行后面的语句labelCounts['no']=1
'''
1)labelCounts.keys()列出字典所有的key,什么是key,就是mapreduce方法当中的key-value,键值对
dict = { 1 : 2, 'a' : 'b', 'hello' : 'world' }
dict.keys()
['a', 1, 'hello']
()
2)在Python当中用tab来进行缩进,这个地方if相对于前面的for是缩进了的,因此是for循环的子判断
'''
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1 #Label计数
'''
1)labelCounts[currentLabel] = labelCounts[currentLabel]+1
2)这个地方需要注意的是,labelCounts[currentLabel] += 1 和if语句的缩进相同
因此它不是if语句的一部分,而是for语句的一部分,同理后面的shannonEnt = 0.0
它并不是for语句的一部分,而是calcShannonEnt这个函数(方法)的一部分
'''
shannonEnt = 0.0 #经验熵(香农熵)
'''
Python定义变量的方法和scala有一些类似,并不像Java那样需要声明变量的类型,而是直接进行类型推断即可
相比于Scala,Python更省,甚至连val都省略掉了
'''
for key in labelCounts: #计算香农熵
prob = float(labelCounts[key]) / numEntires #选择该标签(Label)的概率
shannonEnt -= prob * log(prob, 2) #利用公式计算
return shannonEnt #返回经验熵(香农熵)
if __name__ == '__main__':
'''
关于这句话的意思,知乎有不少答案
1)__name__ 是当前模块名,当模块被直接运行时模块名为 __main__ 。
这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。
2)编写私有化部分 ,这句代码以上的部分,可以被其它的调用,以下的部分只有这个文件自己可以看见
如果文件被调用了,其他人是无法看见私有化部分的
转自知乎https://www.zhihu.com/question/49136398
'''
dataSet, features = createDataSet()
'''
Python多变量赋值
data = ("shiyanlou", "China", "Python")
name, country, language = data
print(name) ==>"shiyanlou"
print(country) ==>"China"
print(language) ==>"Python"
'''
print(dataSet)
print(calcShannonEnt(dataSet))
\