决策树
决策树是一种机器学习的方法。决策树的生成算法有ID3, C4.5和C5.0等。决策树是一种树形结构,其中每个内部节点表示一个属性上的判断,每个分支代表一个判断结果的输出,最后每个叶节点代表一种分类结果。
决策树是一种十分常用的分类方法,需要监管学习,监管学习就是给出一堆样本,每个样本都有一组属性和一个分类结果,也就是分类结果已知,那么通过学习这些样本得到一个决策树,这个决策树能够对新的数据给出正确的分类。
##### 决策树通常有三个步骤:
特征选择、决策树的生成、决策树的修剪。
- 用决策树分类:从根节点开始,对实例的某一特征进行测试,根据测试结果将实例分配到其子节点,此时每个子节点对应着该特征的一个取值,如此递归的对实例进行测试并分配,直到到达叶节点,最后将实例分到叶节点的类中。
- 决策树学习的目标:根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。
- 决策树学习的本质:从训练集中归纳出一组分类规则,或者说是由训练数据集估计条件概率模型。
- 决策树学习的损失函数:正则化的极大似然函数
- 决策树学习的测试:最小化损失函数
- 决策树学习的目标:在损失函数的意义下,选择最优决策树的问题。
- 决策树原理和问答猜测结果游戏相似,根据一系列数据,然后给出游戏的答案。
决策树的构造
决策树学习的算法通常是一个递归地选择最优特征,并根据该特征对训练数据进行分割,使得各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建。
1) 开始:构建根节点,将所有训练数据都放在根节点,选择一个最优特征,按着这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。
2) 如果这些子集已经能够被基本正确分类,那么构建叶节点,并将这些子集分到所对应的叶节点去。
3)如果还有子集不能够被正确的分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的节点,如果递归进行,直至所有训练数据子集被基本正确的分类,或者没有合适的特征为止。
4)每个子集都被分到叶节点上,即都有了明确的类,这样就生成了一颗决策树。
决策树的特点:
- 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
- 缺点:可能会产生过度匹配的问题
- 适用数据类型:数值型和标称型
首先:确定当前数据集上的决定性特征,为了得到该决定性特征,必须评估每个特征,完成测试之后,原始数据集就被划分为几个数据子集,这些数据子集会分布在第一个决策点的所有分支上,如果某个分支下的数据属于同一类型,则当前无序阅读的垃圾邮件已经正确的划分数据分类,无需进一步对数据集进行分割,如果不属于同一类,则要重复划分数据子集,直到所有相同类型的数据均在一个数据子集内。
If so return 类标签:
Else
寻找划分数据集的最好特征
划分数据集
创建分支节点
for 每个划分的子集
调用函数createBranch()并增加返回结果到分支节点中
return 分支节点
使用决策树做预测需要以下过程:
- 收集数据:可以使用任何方法。比如想构建一个相亲系统,我们可以从媒婆那里,或者通过参访相亲对象获取数据。根据他们考虑的因素和最终的选择结果,就可以得到一些供我们利用的数据了。
- 准备数据:收集完的数据,我们要进行整理,将这些所有收集的信息按照一定规则整理出来,并排版,方便我们进行后续处理。
- 分析数据:可以使用任何方法,决策树构造完成之后,我们可以检查决策树图形是否符合预期。
- 训练算法:这个过程也就是构造决策树,同样也可以说是决策树学习,就是构造一个决策树的数据结构。
- 测试算法:使用经验树计算错误率。当错误率达到了可接收范围,这个决策树就可以投放使用了。
- 使用算法:此步骤可以使用适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。
信息增益
什么是信息增益呢?在划分数据集之前之后信息发生的变化成为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。
熵定义为信息的期望值,如果待分类的事物可能划分在多个类之中,则符号xi 的信息定义为:
x
i
)=−log
2
p(x
i
决策树如何构建的问题
每个节点的位置如何确定?
特征的选择:每次选入的特征作为分裂的标准,都是使得决策树在这个节点的根据你自己选择的标准(信息熵最小、信息增益最大、gini系数最小).
每个节点在哪个值上做划分,确定分支结构呢?
遍历划分的节点的分界值操作来解决这个问题
可以想象,我们构造的决策树足够庞大,决策树可以把每一个样本都分对,那么决策树的泛化能力就可以很差了
为了解决这个问题,就需要剪枝操作了
训练算法
基于信息熵的构造
当选择某个特征作为节点时,我们就希望这个特征的信息熵越小越好,那么不确定性越小
H(x)=−pi(x)logpi(x)=−njSlognjS
nj: 第j个类别,在样本中出现的频数
S: 样本个数
对于离散属性,直接计算信息熵,连续属性,就需要划分区间,按区间计算信息熵。
基于某一层的数据集 a. 遍历计算所有属性,遍历相应属性以不同值为分截点的信息熵 b. 选择信息熵最小的作为节点
如果到达终止条件,返回相应信息,否则,按照分支重复步骤1
ID3算法: 信息增益最大化
C:类别
H©=−∑i=1mpilogpi2
按照D组划分C
H(C/D)=∑i=1v|Ci||C|H(Ci)
信息增益
gain(D)=gain©−H(C/D)
决策树单个节点选择的代码实现
def split(X,y,d,value):
'''
在d纬度上,按照value进行划分
'''
index_a =(X[:,d]<=value)
index_b =(X[:,d]>value)
return X[index_a],X[index_b],y[index_a],y[index_b]
from collections import Counter
from math import log
from numpy as np
def entropy(y):
counter = Counter(y) # 字典
res = 0.0
for num in counter.values():
p = num/len(y)
res+=-p*log(p)
return res
def gain(X,y,d,v):
X_l,X_r,y_l,y_r = split(X,y,d,v)
e = len(y_l)/len(y)*entropy(y_l)+len(y_r)/len(y)*entropy(y_r)
return (entropy(y)-e)
def gainratio(X,y,d,v):
X_l,X_r,y_l,y_r = split(X,y,d,v)
gain =entropy(y) - len(y_l)/len(y)*entropy(y_l)+len(y_r)/len(y)*entropy(y_r)
return gain/(entropy(y_l)+entropy(y_r))
def gini(y):
counter = Counter(y)
res = 1.0
for num in counter.values():
p = num / len(y)
res += -p**2
return res
#X_l,X_r,y_l,y_r = split(X,y,d,v)
#return 1-(len(y_l)/len(y))**2-(len(y_r)/len(y))**2
def try_split(X,y):
best_entropy = float('inf')
best_d,best_v=-1,-1
for d in range(X.shape[1]):
sorted_index = np.argsort(X[:,d])
for i in range(1, len(X)):
if (X[sorted_index[i],d] != X[sorted_index[i-1],d]):
v = (X[sorted_index[i-1],d]+X[sorted_index[i],d])/2
X_l,X_r,y_l,y_r = split(X,y,d,v)
# 信息熵
e = entropy(y_l)+entropy(y_r)
#gini
e = gini(y_l) + gini(y_r)
# 信息增益
e = -gain(X,y,d,v)
if e < best_entropy:
best_entropy, best_d,best_v = e,d,v
return best_entropy, best_d, best_v
# 手动来划分
data =np.array([[ 0.3 , 5 , 2 , 0 ],
[ 0.4 , 6 , 0 , 0 ],
[ 0.5 , 6.5 , 1 , 1 ],
[ 0.6 , 6 , 0 , 0 ],
[ 0.7 , 9 , 2 , 1 ],
[ 0.5 , 7 , 1 , 0 ],
[ 0.4 , 6 , 0 , 0 ],
[ 0.6 , 8.5 , 0 , 1 ],
[ 0.3 , 5.5 , 2 , 0 ],
[ 0.9 , 10 , 0 , 1 ],
[ 1 , 12 , 1 , 0 ],
[ 0.6 , 9 , 1 , 0 ],
])
X =data[:,0:3]
y = data[:,-1]
# 手动来划分
best_entropy, best_d, best_v = try_split(X, y)
print(best_entropy, best_d, best_v)
X1_l, X1_r, y1_l, y1_r = split(X,y,best_d,best_v)
print(X1_l, X1_r, y1_l, y1_r)
best_entropy2, best_d2, best_v2 = try_split(X1_r, y1_r)
X2_l, X2_r, y2_l, y2_r = split(X1_r,y1_r,best_d2,best_v2)
entropy(y2_l)
Python sklean里面tree模块里面的DecisionTreeClassifier
from sklearn import tree
clf =tree.DecisionTreeClassifier(max_depth=1,criterion ='gini') # criterion='entropy|gini'
clf = clf.fit(X,y)
训练好一颗决策树之后,我们可以使用export_graphviz导出器以Graphviz格式导出树。
import graphviz
dot_data = tree.export_graphviz(clf, out_file=None,)
graph = graphviz.Source(dot_data)
graph.render("data")