写在之前
之前的博文较为详细介绍了scikit的参数和说明:http://www.jianshu.com/p/59b510bafb4d
本文是在此基础上做的一个应用,涉及的数据和程序可以在下面的连接中下载:http://pan.baidu.com/s/1o8rW4m2
如需转载,请注明出处。如有错误,烦请指正。
关于决策树
决策树是一种典型的分类方法,功能强大且容易提取规则,利用归纳算法生成决策树,树中每一条路径代表一个规则,所以比较适合用于数据挖掘中的分类。
ID3
ID3算法主要针对属性选择问题。是决策树学习方法中最具影响和最为典型的算法。该算法是在树的各个内部节点处寻找一个属性,该属性能最好地将训练集进行分类。依据贪婪算法,为了使下一步所需的信息量最小,要求每一次都选择其信息增益最大的属性作为决策树的新节点。
算法步骤
- 如果数据库中的数据都属于同一个类,N就是树叶,在树叶上 标出所属的类;如果数据表中没有其他属性可以考虑,则N也是树叶,按照少
数服从多数的原则在树叶上标出所属类别。否则,根据平均信息期望值E或GAIN值选出一个最佳属性作为节点N的测试属性 - 节点属性选定后,对于该属性中的每个值:从N生成一个分支,并将数据表中与该分支有关的数据收集形成分支节点的数据表,如果分支数据表非空,则运用以上方法从该节点进一步建立子树。
C4.5
在应用连续属性值时,在一个树结点可以将属性Ai的值划分为几个区间。然后信息增益的计算就可以采用和离散值处理一样的方法。原则上可以将Ai的属性划分为任意数目的空间。C4.5一般包含3种类型的检验结构:
- 离散属性的“标准检验”,对属性的每个可能值有一个分支和输出
- 如果Y有连续的数值,则比较该值和阈值,来定义输出为Y<=Z和Y>Z的二元检验
- 更复杂的检验也基于离散值,属性的每个可能值都分配到数量可变的组中,每组都有一个输出和分支
检验连续属性可以根据算法计算出最右的阈值:首先根据属性值Y移除重复值并对训练样本排序,结果用{V_1, V_2,···,V_m}表示。介于V_i和V_i+1之间阈值将样本划分成{V_1, ···V_i}和{V_{i+1},···V_m}两个区间。系统检查所有分区,分别求用每个数字拆分的信息增益,然后找出使信息增益获得最大的拆分值,以求得最优分区。通常选择(V_i+V_{i+1})/2作为阈值。C4.5一般选择V_i作为阈值。这确保了决策树实际的阈值存在于数据库中。
过度拟合
实际应用中,当数据中有噪声或训练样例的数量太少以至于不能产生目标函数的有代表性的采样时,产生的树会过度拟合。简单的表现为:训练集的误差会比测试集的误差高。
解决过度拟合:
- 及早停止树增长;
- 后修剪法。
后修剪法
将决策树规则化按决策树从左往右的顺序,用if-then写出各个规则,并计算各个规则的精度,对于准确率为100%的规则进行保留,否则需要将if中的条件重新,找到能够使得准确率最高的一组组合,代替原来的规则。
实验部分
数据分析:影响因素有天气、温度、风况、运动。需要根据这四个决定是否运动。其中温度和湿度是连续数据,所以不能用ID3的算法,而天气、风况、运动需要转换成数值型的数据,以便于计算机进行分类。
实现方法:本着不重复造轮子的原则,如果需要快速实现,只需要使用sklearn中的DecisionTreeClassifier就能快速实现,并利用pydotplus快速实现决策树的可视化
程序部分
import pandas as pd
from pandas import Series
import numpy as np
import pydotplus
from sklearn import tree
from sklearn.externals.six import StringIO
# load data
datadic = 'data/data1.xls'
mydata = pd.read_excel(datadic)
# prepare
whetherlist = []
windlist =[]
resultlist = []
for i in range(len(mydata)):
if mydata.ix[i][u'天气'] == u'晴':
whetherlist.append(0)
elif mydata.ix[i][u'天气'] == u'多云':
whetherlist.append(1)
elif mydata.ix[i][u'天气'] == u'有雨':
whetherlist.append(2)
if mydata.ix[i][u'风况'] == u'有':
windlist.append(1)
elif mydata.ix[i][u'风况'] == u'无':
windlist.append(0)
if mydata.ix[i][u'运动'] == u'适合':
resultlist.append(1)
elif mydata.ix[i][u'运动'] == u'不适合':
resultlist.append(0)
mydata[u'天气']=Series(whetherlist)#将中文数据数值化
mydata[u'风况']=Series(windlist)
mydata[u'运动']=Series(resultlist)
xdata = mydata.values[:,:4]
ydata = mydata.values[:,4]
# 建模:min_sample_split将划分进行到底,如果设置是默认的2的时候将会有一部分划分不准确,但是这样做有过拟合的风险
clf = tree.DecisionTreeClassifier(criterion='entropy',min_samples_split=1)#信息熵作为划分的标准,CART
clf = clf.fit(xdata, ydata)
dot_data = StringIO()
tree.export_graphviz(clf, out_file=dot_data,feature_names=['whether','Temperature',\
'wet','wind'], class_names=['no', 'yes'], filled=True, rounded=True, special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
#导出
graph.write_pdf('sport.pdf')
graph.write_png('sport.png')