I I I k n o w know know n o t h i n g nothing nothing b u t but but m y my my i g n o r a n c e . ignorance. ignorance.
基本流程
注意:
- 第二种返回情况,是在利用当前节点的后验分布
- 第三种返回情况,是把父节点的样本分布作为当前节点的先验分布
e x a m p l e example example l i k e like like t h i s this this:
- 第一种
样本的分类都是 1,所以不需要在进行属性划分了,直接将类别标记为 1。
年龄 | 性别 | Y |
---|---|---|
18 | 男 | 1 |
19 | 女 | 1 |
- 第二种
样本中属性年龄和性别都是一样的,而 类别 0 出现最多,所以类别应该标记为 0
年龄 | 性别 | Y |
---|---|---|
18 | 男 | 1 |
18 | 男 | 0 |
18 | 男 | 0 |
- 第三种
按性别对样本进行划分,则会出现数据集 D v ( 性 别 为 女 ) Dv(性别为女) Dv(性别为女) 为空,分类标记为 1(因为 类别 1 最多)
年龄 | 性别 | Y |
---|---|---|
18 | 男 | 1 |
19 | 男 | 1 |
19 | 男 | 0 |
划分选择
决策树学习的关键是第八行,即如何选择最优划分属性。随着划分过程不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的“纯度”越来越高。
信息增益(ID3决策树)
信息熵 ( i n f o r m a t i o n (information (information e n t r o p y ) entropy) entropy) 是度量样本集合纯度最常用的一种指标。假定当前样本集合 D D D中第 k k k类样本所占的比例为 p k ( k = 1 , 2 … , ∣ γ ∣ ) p_k(k=1,2…,|\gamma|) pk(k=1,2…,∣γ∣),则 D D D的 信息熵 定义为:
E n t ( D ) = − ∑ k − 1 ∣ γ ∣ p k l o g 2 p k E n t ( D ) 越 小 , D 的 纯 度 越 高 Ent(D) = -\sum_{k-1}^{|\gamma|}p_klog_2p_k\\ Ent(D)越小,D 的纯度越高 Ent(D)=−k−1∑∣γ∣pklog2pkEnt(D)越小,D的纯度越高
假定离散属性 a a a 有 V V V 个可能的取值 a l , a 2 , . . , a V {a^l,a^2,..,a^V} al,a2,..,aV,若使用 a a a 来对样本集D进行划分,则会产生 V V V 个分支结点,其中第 v v v 个分支结点包含了 D D D 中所有在属性 a a a 上取值为 a v a^v av 的样本,记为 D v D^v Dv。则把属性 a a a 对样本集 D D D 进行划分所获得的 信息增益 定义为:
G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) Gain(D,a)=Ent(D)-\sum_{v=1}^{V}\frac{|D^v|}{|D|}Ent(D^v) Gain(D,a)=Ent(D)−v=1∑V∣D∣∣Dv∣Ent(Dv)
一般来说,信息增益越大,我们使用 a a a 来进行划分所获得的纯度提升越大。所以决策树的最优属性划分可以是:
a ∗ = a r g m a x G a i n ( D , a ) a ∈ A a* = arg maxGain(D,a)\\ a\in A a∗=argmaxGain(D,a)a∈A
著名的 I D 3 ID3 ID3 决策树学习算法就是以信息增益为准则来选择划分属性的。
增益率(C4.5决策树)
使用增益率选择最优划分 是为了减少信息增益准则对取值数码较多的属性偏好可能带来的不利影响。
增益率 定义为:
G a i n _ r a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) I V ( a ) = − ∑ v = 1 V ∣ D v ∣ D l o g 2 ∣ D v ∣ D I V ( a ) 称 为 属 性 a 的 固 有 值 Gain\_ratio(D,a) = \frac{Gain(D,a)}{IV(a)}\\ IV(a)=-\sum_{v=1}^{V}\frac{|D^v|}{D}log_2\frac{|D^v|}{D}\\ IV(a)称为 属性a的固有值 Gain_ratio(D,a)=IV(a)Gain(D,a)IV(a)=−v=1∑VD∣Dv∣log2D∣Dv∣IV(a)称为属性a的固有值
属性 a a a 可能取值数目越多(V越大),则 I V ( a ) IV(a) IV(a) 的值通常也会越大,增益率减小。显然,如果直接使用增益率最大来选择最优属性的话,就会产生对可取值数目较少的属性偏好带来的影响。因此,需要使用一个启发式:先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。
基尼指数(CART决策树)
CART 决策树使用 基尼指数(
G
i
n
i
i
n
d
e
x
Gini index
Giniindex),来选择划分属性。数据集
D
D
D 的纯度可用基尼值来度量:
G
i
n
i
(
D
)
=
∑
k
=
1
∣
γ
∣
∑
k
′
≠
k
p
k
p
k
′
=
1
−
∑
k
=
1
∣
γ
∣
p
k
2
Gini(D)=\sum_{k=1}^{|\gamma|}\sum_{k'\neq k}p_kp_k'\\ =1-\sum_{k=1}^{|\gamma|}p_k^2
Gini(D)=k=1∑∣γ∣k′=k∑pkpk′=1−k=1∑∣γ∣pk2
CART 是 Classification and Regression Tree 的简称,可用于分类和回归任务
G
i
n
i
(
D
)
Gini(D)
Gini(D) 反映了从数据集
D
D
D 中随机抽取两个样本,其类别标记不一致的概率,
G
i
n
i
(
D
)
Gini(D)
Gini(D) 越小,则数据集 D 的纯度越高。
属性
a
a
a 的基尼指数定义为:
G i n i _ i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) Gini\_index(D,a)=\sum_{v=1}^{V}\frac{|D^v|}{|D|}Gini(D^v) Gini_index(D,a)=v=1∑V∣D∣∣Dv∣Gini(Dv)
最优划分属性 a ∗ = a r g m i n G i n i _ i n d e x ( D , a ) a* = argminGini\_index(D,a) a∗=argminGini_index(D,a)
# 西瓜数据集
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('ggplot')
%matplotlib inline
# 对中文的支持
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_csv('watermelon.data')
df.head()
编号 | 色泽 | 根蒂 | 敲声 | 纹理 | 脐部 | 触感 | 密度 | 含糖率 | 好瓜 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 青绿 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 0.697 | 0.460 | 是 |
1 | 2 | 乌黑 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 硬滑 | 0.774 | 0.376 | 是 |
2 | 3 | 乌黑 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 0.634 | 0.264 | 是 |
3 | 4 | 青绿 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 硬滑 | 0.608 | 0.318 | 是 |
4 | 5 | 浅白 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 0.556 | 0.215 | 是 |
# 求信息熵
def ent(data,a):
info_ent = {} # 信息熵
root = '好瓜'
# 求根节点信息熵
# if a==root:
if a ==root:
pi = data[root].value_counts()/len(data)
return np.sum(-pi*np.log2(pi))
# 子节点信息熵
a_val = data[a].value_counts() # 属性 a = {D1,D2,..,Dv}
a_index = a_val.index # example-> ['乌黑', '青绿', '浅白']
for d in a_index:
# d = '乌黑'...
temp_data = data[data[a]==d]
pi = temp_data[root].value_counts()/len(temp_data)
info_ent[d] = np.sum(-pi*np.log2(pi))
return info_ent
# 求信息增益
def gain(data,a):
info_gain = ent(data,'好瓜') # 信息增益
# print("根节点信息熵:%f"%info_gain)
info_ent = ent(data,a)
Pd = data[a].value_counts()/len(data[a]) # Dv/D
for k,v in info_ent.items():
info_gain -= Pd[k]*v
return info_gain
# 求属性 a 的固有值
def iv(dt,a):
filt = dt[a].value_counts()
iv_a = 0
for i in filt:
iv_a -= np.abs(i/filt.sum())*np.log2(i/filt.sum())
return iv_a
# 增益率
def grain_ratio(dt,a):
iv_a = iv(dt,a)
gain_a = gain(dt,a)
gr = gain_a/iv_a
# print(a+"的增益率:%f"%gr)
return gr
# 求 数据集 D 的基尼值
def gini(dt):
filt = dt.iloc[:,-1].value_counts()
gini_d = 1
for i in filt:
gini_d -= (i/filt.sum()) **2
return gini_d
# 属性 a 的基尼指数
def gini_index(dt,a):
gd = 0
a_val = attr[a]
filt = dt[a].value_counts()
for i in filt.index:
Dv = dt[dt[a]==i]
gd += (filt[i]/filt.sum())*gini(Dv)
return gd
# 根据信最大息增益 从 A 中选择最优划分属性 【ID3 决策树】
def get_gain_max_a(dt,index_A):
gain_list = []
for ad in index_A:
gain_list.append(gain(dt,ad))
gain_max = np.max(gain_list)
arg = np.argmax(gain_list)
# 最优属性
best_a = index_A[arg]
index_A.remove(best_a)
return best_a,gain_max
# 根据增益率 选择最优划分属性 【C4.5决策树】
def get_gainrate_max_a(dt,index_A):
gain_list = []
for ad in index_A:
gain_list.append(gain(dt,ad))
# 平均信息增益
mean_gain = np.mean(gain_list)
gain_list = np.array(gain_list)
np_index = np.array(index_A)
args = np.where(gain_list>=mean_gain)
# 高于平均信息增益的属性
up_mean_a = np_index[args]
# 求增益率
gain_rate_list = [grain_ratio(dt,a) for a in up_mean_a]
# 高于平均信息增益属性中的最大增益率
max_gain_rate = np.max(gain_rate_list)
# 下标
arg = np.argmax(gain_rate_list)
# 最优属性
best_a = up_mean_a[arg]
index_A.remove(best_a)
return best_a,max_gain_rate
# 根据最小基尼指数选择最优划分属性 【CART 决策树】
def get_gini_min_a(dt,index_A):
gini_list = []
for ad in index_A:
gini_list.append(gini_index(dt,ad))
arg = np.argmin(gini_list)
min_gini_index = np.min(gini_list)
# 基尼指数最小的属性
best_a = index_A[arg]
index_A.remove(best_a)
return best_a,min_gini_index
# 获取所有属性对应的可能取值:
def get_attr(dt):
"""
return like this:
{'色泽':{'青绿','浅白','乌黑']}...}
"""
attr = {}
col = dt.columns
for c in col:
attr[c]= set(dt[c])
return attr
# 判断 D 中样本在 A 上取值是否相同
def check(dt):
col = dt.columns[:-1]
for i in col:
if len(set(dt[i]))!=1:
return False
return True
# 基本决策树流程
def treeG(dt,A,attr):
# 默认最后一行为标签
Y = dt.iloc[:,-1].value_counts() #.index
# 属性集 A = {a1,a2,..,ad}
index_A = list(A)
# 如果样本属于同一类别 C,则返回
if len(Y)==1:
# 将 节点标记为 类别 C
print("好瓜:"+str(Y.index[0]))
return '无需划分'
# 如果 A 属性集为空或 D中样本在 A 上取值相同
if len(index_A)==0 or check(dt):
m = dt.iloc[:,-1].value_counts()
geq = np.argmax(m)
print(geq)
return '无法划分'
# 从 A 中选择最优划分属性 即 求最大信息熵对应的属性 a*
max_a,gain_max= get_gain_max_a(dt,index_A) # id3 决策
# max_a,gain_rate_max = get_gainrate_max_a(dt,index_A) # C4.5 决策
# max_a,gini_index_min = get_gini_min_a(dt,index_A) # CART 决策
# print(max_a,gain_max)
# 根据属性 a* 分类数据集然后遍历 eg: a_v in ['清晰','稍糊','模糊']
for a_v in attr[max_a]:
Dv = dt[dt[max_a]==a_v][index_A+[Y.name]]
print(max_a,gain_max,'--%s-->'%a_v)
if len(Dv)==0:
m = dt.iloc[:,-1].value_counts()
geq = np.argmax(m)
print("好瓜:"+geq)
return '不能划分'
else:
treeG(Dv,index_A,attr)
dt = df.iloc[:,[1,2,3,4,5,6,-1]]
A = list(df.columns[[1,2,3,4,5,6]])
Y = '好瓜'
dt
色泽 | 根蒂 | 敲声 | 纹理 | 脐部 | 触感 | 好瓜 | |
---|---|---|---|---|---|---|---|
0 | 青绿 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 是 |
1 | 乌黑 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 硬滑 | 是 |
2 | 乌黑 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 是 |
3 | 青绿 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 硬滑 | 是 |
4 | 浅白 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 是 |
5 | 青绿 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 软粘 | 是 |
6 | 乌黑 | 稍蜷 | 浊响 | 稍糊 | 稍凹 | 软粘 | 是 |
7 | 乌黑 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 硬滑 | 是 |
8 | 乌黑 | 稍蜷 | 沉闷 | 稍糊 | 稍凹 | 硬滑 | 否 |
9 | 青绿 | 硬挺 | 清脆 | 清晰 | 平坦 | 软粘 | 否 |
10 | 浅白 | 硬挺 | 清脆 | 模糊 | 平坦 | 硬滑 | 否 |
11 | 浅白 | 蜷缩 | 浊响 | 模糊 | 平坦 | 软粘 | 否 |
12 | 青绿 | 稍蜷 | 浊响 | 稍糊 | 凹陷 | 硬滑 | 否 |
13 | 浅白 | 稍蜷 | 沉闷 | 稍糊 | 凹陷 | 硬滑 | 否 |
14 | 乌黑 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 软粘 | 否 |
15 | 浅白 | 蜷缩 | 浊响 | 模糊 | 平坦 | 硬滑 | 否 |
16 | 青绿 | 蜷缩 | 沉闷 | 稍糊 | 稍凹 | 硬滑 | 否 |
# ent(dt,'色泽')
attr = get_attr(dt)
treeG(dt,A,attr)
纹理 0.3805918973682686 --模糊-->
好瓜:否
纹理 0.3805918973682686 --清晰-->
根蒂 0.45810589515712374 --硬挺-->
好瓜:否
根蒂 0.45810589515712374 --蜷缩-->
好瓜:是
根蒂 0.45810589515712374 --稍蜷-->
色泽 0.2516291673878229 --青绿-->
好瓜:是
色泽 0.2516291673878229 --乌黑-->
触感 1.0 --软粘-->
好瓜:否
触感 1.0 --硬滑-->
好瓜:是
色泽 0.2516291673878229 --浅白-->
好瓜:是
纹理 0.3805918973682686 --稍糊-->
触感 0.7219280948873623 --软粘-->
好瓜:是
触感 0.7219280948873623 --硬滑-->
好瓜:否
根据信息增益生成的决策树如下: