第一个例子是基于假想的服务器日志数据构建决策树,我们利用构建好的决策树来预测用户是否可能成为付费用户。
数据集
# -*- coding: utf-8 -*-
"""
Created on Mon May 16 15:31:51 2016
@author: ZM
"""
my_data=[['slashdot','USA','yes',18,'None'],
['google','France','yes',23,'Premium'],
['digg','USA','yes',24,'Basic'],
['kiwitobes','France','yes',23,'Basic'],
['google','UK','no',21,'Premium'],
['(direct)','New Zealand','no',12,'None'],
['(direct)','UK','no',21,'Basic'],
['google','USA','no',24,'Premium'],
['slashdot','France','yes',19,'None'],
['digg','USA','no',18,'None'],
['google','UK','no',18,'None'],
['kiwitobes','UK','no',19,'None'],
['digg','New Zealand','yes',12,'Basic'],
['slashdot','UK','no',21,'None'],
['google','UK','yes',18,'Basic'],
['kiwitobes','France','yes',19,'Basic']]
节点对象
- 每一个节点都有5个属性,这5个属性都是在initializer中设置,包括:
col——待检验的判断条件所对应的列索引值(分裂属性的Index)
value——对应于为了使结果为true,当前列必须匹配的值(分裂值)
tb,fb——都是decisionnode,它们对应于结果分别为true和false时,相对于当前节点的字树上的节点
result——保存的是针对当前分支的结果,是一个字典。除叶子节点外,在其他节点上该值都为None
class decisionnode:
def __init__(self,col=-1,value=None,results=None,tb=None,fb=None):
self.col=col
self.value=value
self.results=results
self.tb=tb
self.fb=fb
分支
- 在某一列上column对数据集rows进行拆分,能够处理数值型数据或名字性数据
数值型数据——拆分的依据是大于或者小于value
名词性数据——拆分的依据是是否等于value
def divideset(rows,column,value):
# 定义一个函数,令其告诉我们数据行属于第一组(返回值为true)还是第二组(返回值为false)
split_function=None
if isinstance(value,int) or isinstance(value,float):
split_function=lambda row:row[column]>=value
else:
split_function=lambda row:row[column]==value
# 将数据集拆分为两个集合,并返回
set1=[row for row in rows if split_function(row)]
set2=[row for row in rows if not split_function(row)]
return set1,set2
统计票数
我们需要一个函数来对数据集合中的每一项结果进行计数,每一行元素的类别存储在row的最后一列数据中。
def uniquecounts(rows):
results={}
for row in rows:
r=row[len(row)-1]
if r not in results:
results[r]=0
results[r]+=1
return results
基尼不纯度
基尼不纯度:是指将来自集合中的某种结果随机应用于集合中某一数据项的预测误差率
该函数利用集合中每一项结果出现的次数除以集合的总行数来计算相应的概率,然后将所有。这些概率值乘积累加起来,这样就会得到某一行数据被随机分配到错误结果的总概率。
# 随机放置的数据项出现于错误分类中的概率
def giniimpurity(rows):
total=len(rows)
counts=uniquecounts(rows)
imp=0
for k1 in counts:
p1=float(counts[k1])/total
for k2 in counts:
if k1==k2:
continue
p2=float(counts[k2])/total
imp+=p1*p2
return imp
熵
熵:代表的是集合的无序程度——相当于我们所说的集合的混杂程度
def entropy(rows):
from math import log
log2=lambda x :log(x)/log(2)
results=uniquecounts(rows)
# 此处开始计算熵的值
ent=0.0
for r in results:
p=float(results[r])/len(rows)
ent=ent-p*log2(p)
return ent
长树
为了找到分裂属性,我们首先需要计算整个数据集的熵,然后尝试利用每个属性的可能取值 对数据集进行拆分,并求出新分裂的数据集的熵。
信息增益:指当前熵与两个新数据集经加权平均后的熵之间的差值
长树的过程如下
- 遍历每个属性(类属性除外)的每种取值所带来的信息增益,找到最佳分裂属性和最佳分裂值
- 将数据集进行分裂,创建左右分支
- 创建当前节点,赋予当前节点所有属性(包括2中创建的左右分支)
- 若最佳信息增益为负值,表示不能再分,将此节点创建为叶子节点,叶子节点返回当前节点的类别计数
def buildtree(rows,scoref=entropy):
if len(rows)==0:
return decisionnode()
current_score=scoref(rows)
# 定义一些变量以记录最佳拆分条件
best_gain=0
best_criteria=None
best_sets=None
column_count=len(rows[0])-1
for col in range(0,column_count):
# 在当前列中生成一个由不同值构成的序列
column_values={}
for row in rows:
column_values[row[col]]=1