决策树与随机森林

随机森林就是通过集成学习的思想将多棵树集成的一种算法,它的基本单元是决策树,而它的本质属于机器学习的一大分支——集成学习(Ensemble Learning)方法

目录

一、决策树

1,介绍

2,Gini系数(CART决策树)

3,信息熵、信息增益          

4,决策树算法

1,CART算法思想

2,ID3

5,决策树题目

EG1

EG2

EG3

EG4                              

EG5

EG6

EG7

EG8 

EG9

EG10

二、西瓜数据集——决策树ID3

1.导入数据

 2,信息增益:

 1)以基尼系数为例,计算信息增益:

 2)以基尼系数为例,计算信息增益:

3)尝试所有可能,看各种条件下的信息增益谁最大

 4)找出最大收益的节点进行分割

 5)重复步骤四

 6)sklearn决策树

 

二,随机森林

1,介绍

2,python实现

3,随机森林分类器sklearn代码——RandomForestClassifier

1,红酒​​​​​​​

2,西瓜

 三,延展算法

1,堆叠法——StackingClassifier

1,红酒

 2,西瓜

 2,AdaBoost推进法

1,红酒

2,西瓜

 


 

 

一、决策树

1,介绍

决策树(decision tree):是一种基本的分类与回归方法。基本原理是通过对一系列问题进行if/else的推导,最终实现相关决策。

 通过连续的逻辑判断得出最后的结论,其关键在于如何建立这样一棵“树”。

2,Gini系数(CART决策树)

决策树模型的建树依据主要用到的是基尼系数的概念。

基尼系数(gini)用于计算一个系统中的失序现象,即系统的混乱程度(纯度)基尼系数越高,系统的混乱程度就越高(不纯),建立决策树模型的目的就是降低系统的混乱程度(体高纯度),从而得到合适的数据分类效果。

                                                gif.latex?%5Coperatorname%7BGini%7D%28T%29%3D1-%5Csum%20p_%7Bi%7D%5E%7B2%7D

其中gif.latex?p_i为类别i在样本gif.latex?T中出现的频率,即类别为gif.latex?i的样本占总样本个数的比率。

就像,一个全部都是坏瓜的样本中只有一个类别——坏瓜,其出现的频率是100%,所以该系统的基尼系数为1-1^2=0,表示该系统没有混乱,或者说该系统的“纯度”很高。

而如果样本中一半是好瓜,另一半是坏瓜,那么类别个数为2,每个类别出现的频率都为50%,所以其基尼系数为1-(0.5^2+0.5^2)=0.5,即其混乱程度很高。


 当引入某个用于分类的变量时,分类后的基尼系数为:

                                         gif.latex?%5Coperatorname%7Bgini%7D%28T%29%3D%5Cfrac%7BS_%7B1%7D%7D%7BS_%7B1%7D+S_%7B2%7D%7D%20%5Coperatorname%7Bgini%7D%5Cleft%28T_%7B1%7D%5Cright%29+%5Cfrac%7BS_%7B2%7D%7D%7BS_%7B1%7D+S_%7B2%7D%7D%20%5Coperatorname%7Bgini%7D%5Cleft%28T_%7B2%7D%5Cright%29

def Gini(data):
    n0 = sum(data['好瓜']==0)
    n1 = sum(data['好瓜']==1)
    if n0==0 or n1==0:
        return 0
    else:
        n = n0 + n1 
        p0 = n0/n
        p1 = n1/n
        return p0*(1-p0) + p1*(1-p1)
        # return 1 - p0*p0 - p1*p1  # 这是另外一种写法

3,信息熵、信息增益          

除了基尼系数,还有另一种衡量系统混乱程度的经典手段——信息熵。

在搭建决策树模型时,信息熵的作用和基尼系数是基本一致的,都可以帮助合理地划分节点。

信息熵H(X)的计算公式如下。

                                        gif.latex?H%28X%29%3D-%5Csum%20p_%7Bi%7D%20%5Clog%20_%7B2%7D%5Cleft%28p_%7Bi%7D%5Cright%29

其中X表示随机变量,随机变量的取值为X1,X2,X3…,在n分类问题中便有n个取值

当引入某个用于进行分类的变量A,则根据变量A划分后的信息熵又称为条件熵,其计算公式如下。

                                        gif.latex?%5Coperatorname%7BH_A%7D%28X%29%3D%5Cfrac%7BS_%7B1%7D%7D%7BS_%7B1%7D+S_%7B2%7D%7D%20%5Coperatorname%7BH%7D%5Cleft%28X_%7B1%7D%5Cright%29+%5Cfrac%7BS_%7B2%7D%7D%7BS_%7B1%7D+S_%7B2%7D%7D%20%5Coperatorname%7BH%7D%5Cleft%28X_%7B2%7D%5Cright%29

其中S1、S2为划分后的两类各自的样本量,H(X1)、H(X2)为两类各自的信息熵。                                 

def H(data):
    n0 = sum(data['好瓜']==0)
    n1 = sum(data['好瓜']==1)
    if n0==0 or n1==0:
        return 0
    else:
        n = n0 + n1 
        p0 = n0/n
        p1 = n1/n
        return p0*(-np.log(p0)) + p1*(-np.log(p1))

为了衡量不同划分方式降低信息熵的效果,还需要计算分类后信息熵的减少值(原系统的信息熵与分类后系统的信息熵之差),该减少值称为熵增益或信息增益,其值越,说明分类后的系统混乱程度越,即分类越准确

                                                gif.latex?%5Coperatorname%7BGain%7D%28A%29%3DH%28X%29-H_%7BA%7D%28X%29or

                                                gif.latex?%5Coperatorname%7BGain%7D%28A%29%3DGini%28X%29-Gini_%7BA%7D%28X%29


4,决策树算法

ID3/C4.5/CART算法的区别在于选择特征作为判断节点时的数据纯度函数(标准)不同。ID3算法使用的是信息增益,C4.5算法使用的是信息增益比,CART算法使用的是基尼系数(GINI)

1,CART算法思想

CART算法是一种二分递归分割方法,把当前样本划分为两个子样本,不断递归分割使得生成的每个非叶子结点都有两个分支。所以,CART算法生成的决策树是一个二叉树。由于二叉树的每个节点的选择都只有“是”和“否”两种,所以即使一个节点下需要多分类,也是把数据分成两部分。

 

2,ID3

ID3算法使用的数据特征函数(标准)为信息增益。

5,决策树题目

EG1

1)下列说法正确的是?

A、训练决策树的过程就是构建决策树的过程

B、ID3算法是根据信息增益来构建决策树——Gain

C、CART算法是根据基尼不纯度来构建决策树Gini

D、决策树模型的可理解性不高

EG2

2)下列说法错误的是?

A、从树的根节点开始,根据特征的值一步一步走到叶子节点的过程是决策树做决策的过程

B、决策树只能是一棵二叉树

C、非叶子节点分割集合所使用的特征,是使混乱度下降得最多的特征。

EG3

3)用决策树训练一个问题出现过拟合,怎么搞:

A,控制最大深度

B,限制节点中最大的样本中的最小数量

C,限制不纯度的最大值(最小值)

D,更改不纯度计算方法,即模型中的criterion参数

1)当决策树的深度特别深特别深以至于叶子节点中的对象只剩下一个或者很少,导致决策树的模型过于复杂,容易造成过拟合问题,泛化能力下降——控制最大深度(深度小造成欠拟合,深度大造成过拟合) 定义一个高度,当决策树达到该高度时就可以停止决策树的生长,这是一种最为简单的方法

2)达到某个结点的实例具有相同的特征向量,即使这些实例不属于同一类,也可以停止决策树的生长。这种方法对于处理数据中的数据冲突问题非常有效——限制叶子结点处样本的数目

3)定义一个阈值,当达到某个结点的实例个数小于该阈值时就可以停止决策树的生长

EG4

        a618e3058d844d39ab9ce280d751e897.png                                 

 7f1eb9b114f9425899b72304b41bb761.png

 

先算总的Gini(正例和负例)

再计算特征里面的类别(这里就1和0)的正例和负例的Gini

相减的时候,特征Gini要乘以特征的类别对应概率

gif.latex?%5Coperatorname%7BGini%7D%28X%29%3D%5Cfrac%7BS_%7B1%7D%7D%7BS_%7B1%7D+S_%7B2%7D%7D%20%5Coperatorname%7BGini%7D%5Cleft%28X_%7B1%7D%5Cright%29+%5Cfrac%7BS_%7B2%7D%7D%7BS_%7B1%7D+S_%7B2%7D%7D%20%5Coperatorname%7BGini%7D%5Cleft%28X_%7B2%7D%5Cright%29

选B

EG5

a74843e3deb24d9baee6fa4a6891fff8.png

e8b81ee2546341838acdae3695821b9b.png 

 在ensemble里面,决策树在tree

EG6

c6a8f680a5f5482fbdfbdd615ae0e3f1.png

 回归器注意了,criterion参数默认是mse

分类器criterion参数默认是gini

EG7

cc0b85dccf864d7b9d0a87dd99c7049e.png

 D

EG8 

6ca2f2e1ab3a4709a9ec3ab020d1155a.png

 重采样A

​​​​​​​EG9

a040ee2d917349c08c419cf4ad2eec76.png

 重采样B

 

EG10

1550a96c86954361ad3622eb75422322.png

 154c001681da4acbabb87b1c6366d527.png

 

二、西瓜数据集——决策树ID3

1.导入数据

73a32abd05b143af82e34b5e99df410c.png

 2,信息增益:

以敲起来是否沉闷为分割,即以'敲声==0'是否成立来分割:

X1 = watermelon['敲声']
w1 = watermelon[X1==0]
w2 = watermelon[X1!=0]

1f0659b3c99f426587a8497014bbbd89.pngf6f59ed213614e0bb82ed8bfc474c4da.png

 

 1)以基尼系数为例,计算信息增益:

%28n1+n2%29

gif.latex?IG%20%3D%20Gini%28watermelon%29%20-%20p1*Gini%28w1%29%20-%20p2*Gini%28w2%29

n1, n2 = len(w1), len(w2)
p1, p2 = n1/(n1+n2), n2/(n1+n2)
IG = Gini(watermelon) - p1*Gini(w1) - p2*Gini(w2)

eb6d149b87f2467db2f5f5bc9bea629f.png

 2)以基尼系数为例,计算信息增益:

gif.latex?IG%20%3D%20H%28watermelon%29%20-%20p1*H%28w1%29%20-%20p2*H%28w2%29

IG = H(watermelon) - p1*H(w1) - p2*H(w2)

ce6488d851ee43dc9928b1d5dfa609c8.png

 

3)尝试所有可能,看各种条件下的信息增益谁最大

# TODO: 尝试所有可能,即敲声分别为0/1/2、纹理为别为0/1/2,看各种条件下的信息增益谁最大
def CalculateIG(dataset, feature_name, value):
    w1, w2 = splitDataset(dataset, feature_name, value)
    # 计算分割出来的两个子集的比例
    n1, n2 = len(w1), len(w2)
    p1, p2 = n1/(n1+n2), n2/(n1+n2)
    # 以熵为例,计算信息增益
    IG = H(dataset) - p1*H(w1) - p2*H(w2)
    return IG

print(CalculateIG(watermelon, '敲声', 0))
print(CalculateIG(watermelon, '敲声', 1))
print(CalculateIG(watermelon, '敲声', 2))
print(CalculateIG(watermelon, '纹理', 0))
print(CalculateIG(watermelon, '纹理', 1))
print(CalculateIG(watermelon, '纹理', 2))

25ae07b4b3714e518fb06308e0b411a5.png

 4)找出最大收益的节点进行分割

可见是(watermelon, '纹理', 1)为最大收益节点

分割左右节点

def splitDataset(dataset, feature_name, value):
    # 以 'feature_name == value' 是否成立来分割
    series = dataset[feature_name]
    part1 = dataset[series==value]
    part2 = dataset[series!=value]
    return part1, part2
w1, w2 = splitDataset(watermelon, '纹理', 1)
# 找出w1、w2最大收益的节点
print(CalculateIG(w1, '敲声', 0))
print(CalculateIG(w1, '敲声', 1))
print(CalculateIG(w1, '敲声', 2))
print(CalculateIG(w1, '纹理', 0))
print(CalculateIG(w1, '纹理', 2))
print("=================================")
print(CalculateIG(w2, '敲声', 0))
print(CalculateIG(w2, '敲声', 1))
print(CalculateIG(w2, '敲声', 2))
print(CalculateIG(w2, '纹理', 0))
print(CalculateIG(w2, '纹理', 2))

feccb8e75bae4aa3832584d5dee3650f.png

 5)重复步骤四

w3, w4 = splitDataset(w1, '敲声', 2)
w5, w6 = splitDataset(w2, '敲声', 1)
# 找出w3、w4最大收益的节点
print(CalculateIG(w3, '敲声', 0))
print(CalculateIG(w3, '敲声', 1))
print(CalculateIG(w3, '纹理', 0))
print(CalculateIG(w3, '纹理', 2))
print("=================================")
print(CalculateIG(w4, '敲声', 0))
print(CalculateIG(w4, '敲声', 1))
print(CalculateIG(w4, '纹理', 0))
print(CalculateIG(w4, '纹理', 2))

a3b5e24d5e234b1985192fa837b2bc8c.png

 

# 找出w5、w6最大收益的节点
print(CalculateIG(w5, '敲声', 0))
print(CalculateIG(w5, '敲声', 2))
print(CalculateIG(w5, '纹理', 0))
print(CalculateIG(w5, '纹理', 2))
print("=================================")
print(CalculateIG(w6, '敲声', 0))
print(CalculateIG(w6, '敲声', 2))
print(CalculateIG(w6, '纹理', 0))
print(CalculateIG(w6, '纹理', 2))

65b51a855d57469fab02f996146bbb71.png

w7, w8 = splitDataset(w5, '纹理', 0)
w9, w10 = splitDataset(w4, '敲声', 0)
print(CalculateIG(w7, '敲声', 0))
print(CalculateIG(w7, '敲声', 2))
print(CalculateIG(w7, '纹理', 2))
print("=================================")
print(CalculateIG(w8, '敲声', 0))
print(CalculateIG(w8, '敲声', 2))
print(CalculateIG(w8, '纹理', 2))

 b57546d80a06459d962ce861ef77edd0.png

print("=================================")
print(CalculateIG(w9, '敲声', 1))
print(CalculateIG(w9, '纹理', 0))
print(CalculateIG(w9, '纹理', 2))
print("=================================")
print(CalculateIG(w10, '敲声', 1))
print(CalculateIG(w10, '纹理', 0))
print(CalculateIG(w10, '纹理', 2))

 4a9a77f28a37438ab5f19e0f7a5af5aa.png

 6b704c9eadcc445c8fbbcc41f6c6e3e3.png

 6)sklearn决策树

sklearn中决策树模型放在tree包里面

1)决策回归器:DecisionTreeRegressor

重要参数:

criterion="mse" #默认。

"mse"表示使用均方误差;

"friedman_mse"表示使用费尔德曼均方误差;

“mae”表示使用绝对平均误差

2)决策分类器:DecisionTreeClassifier

重要参数:

criterion 这个参数正是用来决定不纯度的计算方法的。sklearn提供了两种选择

1)输入”entropy“,使用信息熵(Entropy)

2)输入”gini“,使用基尼系数(Gini Impurity)(默认)

# 1.建立模型
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
model = DecisionTreeClassifier(criterion='entropy')

# 2.训练模型
X, y = watermelon[['敲声','纹理']], watermelon['好瓜']
model.fit(X, y)

# 3-4.评估模型
y_pred=model.predict(X)
accuracy_score(y, y_pred)

fdf09fefc49b4e7db2967528ed215674.png

 

 

二,随机森林

1,介绍

随机森林(Random Forest,简称 RF ),是以决策树为基学习器的 Bagging 集成算法,它通过自助法(bootstrap)重采样技术,从原始训练样本集N中有放回地重复随机抽取k个样本生成新的训练样本集合,是Bagging 集成算法中性能最强的。

首先森林两个字是非常好理解的,随机森林的基学习器是决策树,成百上千棵决策树就构成了一个森林,这是一种形象的说法。学习到多棵决策树之后,再按照上面所写的 Bagging 中基学习器的结合方法,就可以得到分类或回归的最终预测结果。

随机森林中运用了两个“随机”:

一是样本随机,也就是一般的 Bagging 集成中通过自助采样所得到的效果,也叫做样本扰动,这体现了随机森林继承性的一面。

二是特征随机,也叫属性扰动,体现了随机森林创新的一面。假设训练数据集中的样本有 d 个属性(特征),构成一个属性集合,那么随机森林在构建一棵决策树的过程中,在每一个结点上选择属性进行分裂时,都先从属性集合中随机选择一个包含 k 个属性的属性子集( k<d ),再从这个子集中选择一个最优属性进行分裂。回想一下传统的决策树构建过程,在每一个结点上都是从完整的属性集合(包含 d 个属性)中,选择最佳的属性进行分裂。一般情况下,推荐 k 的值取。

所以随机森林中每棵树生成的规则是:

1、对于包含 m 个样本的原始数据集,通过自助采样得到同样包含 m 个样本的训练集;

2、每个样本有 d 个特征,那么选择一个小于 d 的整数 k ,随机地从 d 个特征中选择 k 个特征,然后决策树在每个结点上进行分裂时,从 k 个特征中选择最优的;

3、每棵树都生长到最大深度,不进行剪枝。

 

1、下列说法正确的是?

A、相比自助法,在初始数据量较小时交叉验证更常用。

B、自助法对集成学习方法有很大的好处

C、使用交叉验证能够增加模型泛化能力

D、在数据难以划分训练集测试集时,可以使用自助法

2)建立随机森林模型时,主要通过什么技术使得各个评估器各不相同:

A,使用可重复抽样得到不同的数据集。

B,使用不同的criterion策略

C,采用不同的剪枝策略

D,使用"random"进行分割策略

2,python实现

建立红酒数据单棵决策树:

data = load_wine()
X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.3)
model = DecisionTreeClassifier(criterion='entropy')
model.fit(X_train, y_train) 
pred_y = model.predict(X_test)
accuracy_score(y_test, pred_y) 

165470de467b45679f619ec22f0f2fff.png

# 1.建立多个决策树
models = [DecisionTreeClassifier(criterion='entropy') for i in range(9)]
predicts = []

for m in models:
    # 2.训练每个决策树
    X, _, y, _ = train_test_split(X_train, y_train, test_size=0.2) # 随机分割代替重采样。
    m.fit(X, y)
    # 3.得到每个决策树的测试结果
    p = m.predict(X_test)
    predicts.append(p)
ps = np.array(predicts).T

# 4.对多个结果进行投票
results=[]
for line in ps:
    results.append(np.argmax(np.bincount(line)))
p = np.array(results)

# 5.对投票结果进行评估
accuracy_score(y_test, p)

c94bc678b5854d5681089282f5aa530a.png

3,随机森林分类器sklearn代码——RandomForestClassifier

sklearn中随机森林模型放在ensemble包里面

重要参数:

1,n_estimators=10:决策树的个数,越多越好,但是性能就会越差,至少100左右(具体数字忘记从哪里来的了)可以达到可接受的性能和误差率。  

2,bootstrap=True:是否有放回的采样。 

1,红酒

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
model = RandomForestClassifier(n_estimators=9) 
model.fit(X_train, y_train) 
pred_y = model.predict(X_test)
accuracy_score(y_test, pred_y) 

 fcee17c4f2d34e70a23eb218e658780b.png

 

2,西瓜

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 用随机森林对西瓜数据集进行学习
model = RandomForestClassifier(n_estimators=9) 
X, y = watermelon[['敲声','纹理']], watermelon['好瓜']
model.fit(X, y) 
y_pred = model.predict(X) 
accuracy_score(y, y_pred)

e9561cdaa6e64a968c0de71a35d3cf68.png

 三,延展算法

1,堆叠法——StackingClassifier

gif.latex?x%20%5Crightarrow【基础模型+基础模型+...+基础模型】gif.latex?%5Crightarrow%20x%27%5Crightarrow%20x%27【元模型】gif.latex?%5Crightarrow%20pred

1,红酒

from sklearn.ensemble import StackingClassifier
# 1.
model = StackingClassifier(
    estimators=[('LR', LogisticRegression(max_iter=1000)), ('NB', GaussianNB())],
    final_estimator=DecisionTreeClassifier(),
)
# 2.
model.fit(X_train, y_train)
# 3.
y_pred = model.predict(X_test) 
# 4.
accuracy_score(y_test, y_pred)

877ac7d11e6d4710a3b1bccb0513d7cf.png

 2,西瓜

from sklearn.ensemble import StackingClassifier
# 1.
model = StackingClassifier(
    estimators=[('LR', LogisticRegression(max_iter=1000)), ('NB', GaussianNB())],
    final_estimator=DecisionTreeClassifier(),
)
# 2.
model.fit(watermelon[['敲声','纹理']], watermelon['好瓜'])
# 3.
y_pred = model.predict(watermelon[['敲声','纹理']]) 
# 4.
accuracy_score(watermelon['好瓜'], y_pred)

0f38905991fe4ce8921b420c48cf77ca.png

 2,AdaBoost推进法

自适应推进,核心思想是“前人栽树,后人乘凉”

1,红酒

from sklearn.ensemble import AdaBoostClassifier
model = AdaBoostClassifier(n_estimators=21, random_state=11)
model.fit(X_train, y_train)
y_pred = model.predict(X_test) 
accuracy_score(y_test, y_pred)

f738a7b2f23d4ca7a6a53dfa5d7f56f5.png

 

2,西瓜

from sklearn.ensemble import AdaBoostClassifier
model = AdaBoostClassifier(n_estimators=10, random_state=10)
model.fit(watermelon[['敲声','纹理']], watermelon['好瓜'])
y_pred = model.predict(watermelon[['敲声','纹理']]) 
# 4.
accuracy_score(watermelon['好瓜'], y_pred)

1f660db230eb476b866ef915cf345d01.png

6781f344b63845c7823ccee13e0611b8.png


 

 

 

 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值