文章目录
主要是分享决策的基本知识点,重点在分类决策树上,对于回归的决策树后面在给出。希望大家和我一起做知识的传播者啦!? ? ? ?
决策树
英文名字:Descision Tree
什么是决策树
举个校园相亲的例子,今天校园的小猫(女)和小狗(男)准备配对,小猫如何才能在众多的优质?的心仪的狗呢?于是呢?有一只特乖巧的小猫找到了你,你正在学习机器学习,刚好学习了决策树,准备给这只猫猫挑选优质狗,当然,你不仅仅是直接告诉猫哪些狗是合适你的?你更应该详细的给猫讲解决策树是如何根据它提出的标准选出的符合要求的狗呢?
猫给出如下信息:
年龄<0.5 不心仪;年龄大于>=0.5 6.5<=体重<=8.5;心仪; 年龄>=0.5 体重>8.5 长相好 心仪;其余情况不心仪; 根据上述条件可以构造一颗树:
上面的图就是决策树,最终的结果是心仪或者不心仪。决策树算法以树形结构表示数据分类的结果
基本概念
决策树属于也只能非参数学习算法、可以用于解决(多)分类问题,回归问题。 回归问题的结果,叶子结点的平均值是回归问题的解。
根节点:决策树具有数据结构里面的二叉树、树的全部属性
非叶子节点 :(决策点) 代表测试的条件,数据的属性的测试
叶子节点 :分类后获得分类标记
分支: 测试的结果
数学问题-熵-Gini系数
什么是熵:熵的概念源于物理学,用于度量一个热力学系统的无序程度。
信息熵:不得不提香农这个大写的人啦!信息论里面的知识。在信息论里面,信息熵衡量信息量的大小,也就是对随机变量不确定度的一个衡量。熵越大,不确定性越大;
对于某个单符号无记忆信源,发出符号(
x
i
x_i
xi)的概率是
p
i
p_i
pi,概率越大,符号的信息量就越小,香农公式
I
(
x
i
)
=
−
l
o
g
p
i
I(x_i)=-log_{p_i}
I(xi)=−logpi。信源所含的信息熵就是信息量的期望]
H
(
x
)
=
−
∑
p
i
∗
l
o
g
p
i
H(x)=-\sum p_i*log_{p_i}
H(x)=−∑pi∗logpi
Gini系数:
G
i
m
i
(
p
)
=
1
−
∑
k
=
1
K
p
k
2
Gimi(p) = 1-\sum_{k=1}^{K}p_k^2
Gimi(p)=1−∑k=1Kpk2
决策树如何构建的问题
自我提问阶段:
每个节点的位置如何确定?
答:每次选入的属性,进行划分,都是使得决策树在这个节点的根据你自己选择的标准(信息熵最小、信息增益最大、gini系数最小).
每个节点在哪个值上做划分,确定分支结构呢?
遍历划分的节点的分界值操作
训练算法
基于信息熵的构造
当选择某个节点时,我们就希望这个节点的信息熵越小越好,那么不确定性越小。
H
(
x
)
=
−
p
i
(
x
)
l
o
g
p
i
(
x
)
=
−
n
j
S
l
o
g
n
j
S
H(x) = -p_i(x)log^{p_i(x)} = -\frac{n_j}{S}log^{\frac{n_j}{S}}
H(x)=−pi(x)logpi(x)=−SnjlogSnj
n
j
n_j
nj: 第j个类别,在样本中出现的频数
S
S
S: 样本个数
对于离散属性,直接计算信息熵,连续属性,就需要划分区间,按区间计算信息熵。
- 基于某一层的数据集
a. 遍历计算所有属性,遍历相应属性以不同值为分截点的信息熵
b. 选择信息熵最小的作为节点 - 如果到达终止条件,返回相应信息,否则,按照分支重复步骤1
ID3算法: 信息增益最大化
C:类别
H
(
C
)
=
−
∑
i
=
1
m
p
i
l
o
g
2
p
i
H(C)=-\sum_{i=1}^{m}p_i log _2^{p_i}
H(C)=−i=1∑mpilog2pi
按照D组划分C
H
(
C
/
D
)
=
∑
i
=
1
v
∣
C
i
∣
∣
C
∣
H
(
C
i
)
H(C/D)=\sum_{i=1}^{v}\frac{|C_i|}{|C|}H(C_i)
H(C/D)=i=1∑v∣C∣∣Ci∣H(Ci)
信息增益
g
a
i
n
(
D
)
=
g
a
i
n
(
C
)
−
H
(
C
/
D
)
gain(D) = gain(C)-H(C/D)
gain(D)=gain(C)−H(C/D)
这里我就以网上给出的数据为例,给出根据信息熵构成决策树的计算过程。
- 确定特征,统计属性值和分解结果,总共四个特征,四种特征的统计结果如下图:
- 根据历史数据,在不知到任何情况下,计算数据本身的熵为
− 9 14 l o g 2 9 14 − 5 14 l o g 2 5 14 = 0.940 - \frac{9}{14}log_2 \frac{9}{14}-\frac{5}{14}log_2\frac{5}{14}=0.940 −149log2149−145log2145=0.940 - 计算每个特征做为节点的信息熵
以天气为例,天气三种属性,当Outlook = sunny时,H(x) = − 2 5 l o g 2 2 5 − 3 5 l o g 2 3 5 -\frac{2}{5}log_2\frac{2}{5}-\frac{3}{5}log_2\frac{3}{5} −52log252−53log253; 当Outlook= overcast, H ( x ) = 0 H(x)=0 H(x)=0,当Outlook = rainy , H ( x ) = 0.971 H(x) = 0.971 H(x)=0.971
所以,当选天气作为节点时,此时 H ( x ) = 5 14 ∗ 0.971 + 4 14 ∗ 0 + 5 14 ∗ 0.971 = 0.693 H(x)=\frac{5}{14}*0.971+\frac{4}{14}*0+\frac{5}{14}*0.971 = 0.693 H(x)=145∗0.971+144∗0+145∗0.971=0.693,gain(天气) = 0.247
同理,可得gain(温度) =0.029 gain(湿度)=0.152,gain(风)=0.048
因此选择天气节点,在递归实现其他节点的选择。
C4.5: 信息增益率
如果这里考虑了一列ID,每个ID出现一次,所以算出的信息增益大。
$ H(x) = 0$,信息增益最大化了,可以引入信息增益率
C
(
T
)
=
信
息
增
益
H
(
T
)
=
H
(
C
)
−
H
(
C
/
T
)
H
(
T
)
C(T) = \frac{信息增益}{H(T)} =\frac{H(C)-H(C/T)}{H(T)}
C(T)=H(T)信息增益=H(T)H(C)−H(C/T)
CART:基尼(Gini)系数
G = 1 − ∑ i = l k k p i 2 G = 1-\sum_{i=l_k}^{k}p_i^2 G=1−i=lk∑kpi2,也是对随机变量不确定性的一个衡量,gini越大,不确定性越大
连续属性的处理方法
选取分解点的问题: 分成不同的区间(二分、三分…),分别计算增益值,然后比较选择。
评价
评价函数:
C
(
T
)
=
∑
r
e
l
e
a
f
N
t
∗
H
(
T
)
C(T) = \sum_{releaf} N_t*H(T)
C(T)=releaf∑Nt∗H(T)
$ N_t$:每个叶子节点里面含有的样本个数
H
(
T
)
H(T)
H(T):叶子节点含有的信息熵
过拟合
如果决策树过于庞大,分支太多,可能造成过拟合。对应训练样本都尽可能的分对,也许样本本身就存在异常点呢?
I. 预剪枝:边构建,边剪枝
- 指定深度d
- 节点的min_sample
II. 后剪枝: 构建好后,然后才开始裁剪
C
α
(
T
)
=
C
(
T
)
+
α
∣
T
l
e
a
f
∣
C_\alpha(T) = C(T)+\alpha|T_{leaf}|
Cα(T)=C(T)+α∣Tleaf∣
在构造含一棵树后,选一些节点做计算,看是否需要剪枝
随机森林
Bootstraping: 有放回采样
Bagging:有放回采样n个样本,建立分类器
一次采样一颗树,多次采样多棵树,构成一片森林,多个分类器共同决定。当有一个test时,代入所以的决策树,共同决策。
随机性的解释:
1. 数据的随机性
为每个树选取训练数据,随机按照比列有放回选择数据集
2. 特征的随机性
按照比列选取特征的个数
决策树单个节点选择的代码实现
简单实现了单个节点决策构造过程
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")
在运行时可以出错:
ExecutableNotFound: failed to execute [‘dot’, ‘-Tpdf’, ‘-O’, ‘data’], make sure the Graphviz executables are on your systems’ PATH
原因:graphviz本身是一个软件,需要额外下载,并将其bin加入环境变量之中。下载