天天看点

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

1.总概述

决策树(desicion tree)是一种树形结构,其中每个内部节点表示在一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一个类别。

决策树以实例为基础进行归纳学习。其采用自上而下的递归方式,基本思路是以信息熵为度量构造一棵熵值下降最快的树,到叶子节点时熵值应该下降为零。此时每个叶节点中包含的实例都为同一类。

2.信息熵

2.1 熵

熵 (entropy) 这一概念来源于热力学,是混乱程度的度量。

而信息熵(information entropy)这一概念在1948年被引入,旨在帮助人们度量一个信息。信息量的度量就等于其不确定性的大小。信息熵的大小与这条信息的确定性成反比。

2.2 条件熵

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

(x,y)发生的熵减去(x)发生的熵,即为在x条件下,y发生的熵。

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

条件熵的推导公式如下:

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

若想了解更多有关机器学习中的熵、条件熵、交叉熵以及相对熵,可以跳转机器学习中的熵。

3.决策树

3.1 信息增益

信息增益表示得知特征A的信息使得使得类X的信息的不确定度减少的程度。信息增益G(D,A)定义为集合D的信息熵H(D)与给定特征条件A下的条件熵H(D,A)之差。这也被称为特征A与数据集D的互信息。

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

信息增益的计算方法如下:

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

3.2 基尼系数

基尼系数(gini coefficient/index )计算方法如下:

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

若想对基尼系数有更多的了解,可前往基尼系数。

3.3 信息增益率

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

3.4 决策树学习算法

3.4.1 ID3

使用信息增益/互信息G(D,A)来进行特征选择。

ID3算法所采用的度量标准就是我们前面所提到的“信息增益”。当属性a的信息增益最大时,则意味着用a属性划分,其所获得的“纯度”提升最大。我们所要做的,就是找到信息增益最大的属性。

3.4.2 C4.5

使用信息增益率来进行特征选择。

实际上,信息增益准则对于可取值数目较多的属性会有所偏好,为了减少这种偏好可能带来的不利影响,C4.5决策树算法不直接使用信息增益,而是使用“信息增益率”来选择最优划分属性。

需要注意的是,增益率准则对可取值数目较少的属性有所偏好。所以一般这样选取划分属性:先从候选属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。

3.4.3 CART

CART(classification and regression train),使用基尼系数来进行特征选择。

一个属性的信息增益(率)/基尼系数越大,表明属性对样本的熵的减少的能力更强,这个属性使得一个数据由不确定变为确定的能力更强。

3.5 损耗函数

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

损耗函数的推导过程可参见损耗函数。

3.6 过拟合

决策树对于训练数据能够有很好的分类能力,但对未知的测试数据却未必能有很好的分类能力,即决策树很有可能产生过拟合的现象。

针对过拟合的现象,有以下两种解决方法。

3.6.1 剪枝

3.6.1.1 概述

三种算法的剪枝过程算法相同,区别仅仅在于对于当前树的评价标准不同。

3.6.1.2 总体思路

由完全树T0开始进行剪枝,剪枝部分结点得到T1,再次剪枝部分结点得到T2,不断重复剪枝部分结点,直至仅剩树根的树Tk。

在验证数据集上对这k个树分别评价,选择损失函数最小的数Ta。

3.6.1.3 剪枝系数的确定

叶节点越多,决策树也就越复杂,损失也就越大。

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

当α=0时,未剪枝的决策树损失最小。当α=+∞时,单根结点的决策树损失最小。

假设此时对以r为根的子树进行剪枝,剪枝后,只保留r本身而删掉所有的叶子。

此时剪枝后的损耗函数:

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

剪枝前的损耗函数:

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

令二者相等,可得:

机器学习 决策树以及随机森林1.总概述2.信息熵3.决策树4.Bagging和随机森林5.代码实践

此时α即为结点r的剪枝系数。

3.6.1.4 剪枝算法

对于给定的决策树T0:

计算所有内部结点的剪枝系数;

查找剪枝系数最小的结点,剪枝得到决策树Tk;

重复上述两个步骤,知道决策树只剩下一个结点;

可以得到决策树序列T0T1T2…Tk;

使用验证样本集选择最优子树,其选择标准可以选用损耗函数。

3.6.2 随机森林

随机森林具体内容见下文。

4.Bagging和随机森林

4.1 Bagging的策略

Bagging(bootstrap aggregation)的策略如下:

从样本集中有重复地选取出n个样本;

在所有属性上,对这个n个样本建立分类器(ID3、C4.5、CART、logistic回归、SVM等等);

重复上述两步m次,即获得了m个分类器;

将数据放在这m个分类器上,最后根据这m个分类器的投票结果,决定数据属于哪一类。

4.2 随机森林

随机森林在Bagging的基础上做了一部分修改。其策略如下:

在样本集中用bootstrap采样选取n个样本;

从所有属性中随机选择k个属性,选择最佳分割属性作为节点建立CART决策树;

重复以上两步m次,即建立了m棵CART决策树;

这m棵CART决策树形成了随机森林,通过投票表决结果,来决定数据属于哪一类。

4.3 随机森林与决策树的关系

使用决策树作为基本分类器,采用Bagging的策略,所形成的总分类器为“随机森林”;但是使用SVM、logistic回归等其他分类器,采用Bagging的策略,所形成的总分类器也被叫做“随机森林”。

5.代码实践

5.1 随机森林分类

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

def iris_type(s):#为了方便之后数据预处理
    it = {b'Iris-setosa': 0, b'Iris-versicolor': 1, b'Iris-virginica': 2}
    return it[s]

# 花萼长度、花萼宽度,花瓣长度,花瓣宽度
iris_feature = u'花萼长度', u'花萼宽度', u'花瓣长度', u'花瓣宽度'

if __name__ == "__main__":
    mpl.rcParams['font.sans-serif'] = [u'SimHei']
    mpl.rcParams['axes.unicode_minus'] = False

    path = '8.iris.data'  # 数据文件路径
    data = np.loadtxt(path, dtype=float, delimiter=',', converters={4: iris_type})
    x, y = np.split(data, (4,), axis=1)
    # 为了可视化,仅使用前两列特征
    x = x[:, :2]
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)

    # 决策树参数估计
    model = Pipeline([
        ('ss', StandardScaler()),
        ('DTC', DecisionTreeClassifier(criterion='entropy', max_depth=3))])
    model = model.fit(x_train, y_train)
    y_test_hat = model.predict(x_test)      # 测试数据

    #画决策树图
    f = open('.\\iris_tree.dot', 'w')
    tree.export_graphviz(model.get_params('DTC')['DTC'], out_file=f)
    f.close()

    N, M = 100, 100  # 横纵各采样多少个值
    x1_min, x1_max = x[:, 0].min(), x[:, 0].max()  # 第0列的范围
    x2_min, x2_max = x[:, 1].min(), x[:, 1].max()  # 第1列的范围
    t1 = np.linspace(x1_min, x1_max, N)
    t2 = np.linspace(x2_min, x2_max, M)
    x1, x2 = np.meshgrid(t1, t2)  # 生成网格采样点
    x_show = np.stack((x1.flat, x2.flat), axis=1)  # 测试点

    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
    y_show_hat = model.predict(x_show)  # 预测值
    y_show_hat = y_show_hat.reshape(x1.shape)  # 使之与输入的形状相同
    plt.figure(facecolor='w')
    plt.pcolormesh(x1, x2, y_show_hat, cmap=cm_light)  # 预测值的显示
    plt.scatter(x_test[:, 0], x_test[:, 1], c=y_test.ravel(), edgecolors='k', s=100, cmap=cm_dark, marker='o')  # 测试数据
    plt.scatter(x[:, 0], x[:, 1], c=y.ravel(), edgecolors='k', s=40, cmap=cm_dark)  # 全部数据
    plt.xlabel(iris_feature[0], fontsize=15)
    plt.ylabel(iris_feature[1], fontsize=15)
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    plt.grid(True)
    plt.title(u'鸢尾花数据的决策树分类', fontsize=17)
    plt.show()

    # 训练集上的预测结果
    y_test = y_test.reshape(-1)
    print (y_test_hat)
    print (y_test)
    result = (y_test_hat == y_test)   # True则预测正确,False则预测错误
    acc = np.mean(result)
    print ('准确度: %.2f%%' % (100 * acc))

    # 过拟合:错误率
    depth = np.arange(1, 15)
    err_list = []
    for d in depth:
        clf = DecisionTreeClassifier(criterion='entropy', max_depth=d)
        clf = clf.fit(x_train, y_train)
        y_test_hat = clf.predict(x_test)  # 测试数据
        result = (y_test_hat == y_test)  # True则预测正确,False则预测错误
        err = 1 - np.mean(result)
        err_list.append(err)
        print (d, ' 错误率: %.2f%%' % (100 * err))
    plt.figure(facecolor='w')
    plt.plot(depth, err_list, 'ro-', lw=2)
    plt.xlabel(u'决策树深度', fontsize=15)
    plt.ylabel(u'错误率', fontsize=15)
    plt.title(u'决策树深度与过拟合', fontsize=17)
    plt.grid(True)
    plt.show()

           

5.2 随机森林回归

import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor

if __name__ == "__main__":
    N = 100
    x = np.random.rand(N) * 6 - 3     # [-3,3)
    x.sort()
    y = np.sin(x) + np.random.randn(N) * 0.05
    x = x.reshape(-1, 1)  # 转置后,得到N个样本,每个样本都是1维的

    reg = DecisionTreeRegressor(criterion='mse', max_depth=9)
    dt = reg.fit(x, y)
    x_test = np.linspace(-3, 3, 50).reshape(-1, 1)
    y_hat = dt.predict(x_test)
    plt.plot(x, y, 'r*', linewidth=2, label='Actual')
    plt.plot(x_test, y_hat, 'g-', linewidth=2, label='Predict')
    plt.legend(loc='upper left')
    plt.grid()
    plt.show()

    # 比较决策树的深度影响
    depth = [2, 4, 6, 8, 10]
    clr = 'rgbmy'
    reg = [DecisionTreeRegressor(criterion='mse', max_depth=depth[0]),
           DecisionTreeRegressor(criterion='mse', max_depth=depth[1]),
           DecisionTreeRegressor(criterion='mse', max_depth=depth[2]),
           DecisionTreeRegressor(criterion='mse', max_depth=depth[3]),
           DecisionTreeRegressor(criterion='mse', max_depth=depth[4])]

    plt.plot(x, y, 'k^', linewidth=2, label='Actual')
    x_test = np.linspace(-3, 3, 50).reshape(-1, 1)
    for i, r in enumerate(reg):
        dt = r.fit(x, y)
        y_hat = dt.predict(x_test)
        plt.plot(x_test, y_hat, '-', color=clr[i], linewidth=2, label='Depth=%d' % depth[i])
    plt.legend(loc='upper left')
    plt.grid()
    plt.show()