机器学习实战之路 —— 3 决策树与随机森林二
1. 随机森林概述
在上一篇博客中已经对决策树算法及实践做了论述,其中就有谈到关于决策树的过拟合问题,随着决策树模型越复杂,则模型适应性越差,越容易发生过拟合的问题。并讲述一般通过剪枝算法来防止决策树过拟合,提高算法泛化性能的方法。
但就此我们可以思考,如果不对决策树进行剪枝,是否有其他提高其泛化性能的方法呢?结合单个分类器组合成多个分类器的思想,一种很容易被想到的办法就是生成多棵决策树,这些决策树不需要都有很高的分类精度,并让所有的决策树通过投票的形式进行决策,这就象多个专家一起开会讨论,最后举手表决一样,这就是随机森林核心的思想。大量的理论和实证研究都证明了随机森林算法具有较高的预测准确率,对异常值和噪声具有很好的容忍度,且不容易出现过拟合。
随机森林中决策树的个数越多,森林的泛化误差就会逐渐收敛。因此,随机森林可很好的避免过拟合问题。 随机森林的准确率依赖于个体分类器的准确率和分类器相互之间的独立性。因此,保持个体分类器的准确率,并保证个体分类器之间尽可能独立,是保证随机森林模型的效果的关键因素。另外随机森林在每次划分时,选取单个或少量特征比多个特征得到的准确率要好。因此,在大型数据集上随机森林也非常有效。
2. 随机森林的构建过程
随机森林本身是基于Bagging思路改进实现的决策树群体模型,所以在此简单介绍Bagging的相关知识。
2.1 Bagging与随机森林
Bagging属于并行式集成学习的一种方法,其主要实现思想如下:如果给出一个数据集具n个样本,对其进行n次随机有放回采样,就得到一个样本量为n的子样本;重复上述步骤m次便可以得到m个子样本,用这m个样本分别去训练m个基学习器;最后将这这些基学习器结合,在对预测值进行组合时,Bagging通常对分类任务采取简单投票法,即所有基学习器预测最多的分类结果作为集成学习器的最终结果,而对于回归任务则是采用取各个预测结果的平均值作为最终结果。Bagging方法利用的是样本的随机性,极大的提高了模型的泛化能力,减少了计算过程中过拟合的现象。
随机森林算法的基础是Bagging方法,随机森林在运算过程中,在样本(行变量)随机性的基础上又增加了属性(列变量)的随机性,这使得随机森林中的个体学习器之间差异度的增加,从而进一步减少过拟合现象的存在。
随机森林的主要构建过程如下:
- 从样本集中用Bootstrap采样选出n个样本
- 从所有属性d中随机选择k个属性,选择最佳分割属性作为节点建立CART决策树
- 重复1、2两个步骤,即建立了m棵CART决策树
- m个CART形成随机森林,通过投票表决结果,决定数据属于哪一类
k 控制了随机性的引入程度;若令 k = d , 则基决策树的构建与传统决策树相同;若令 k = 1 , 则是随机选择一个属性用于划分 ; 一般情况下,推荐值
k
=
l
o
g
2
d
k = log_2 d
k=log2d。
对应的算法示意图如下:
2.2 OOB数据
算法中所采用的重采样,即为评估方法中的自助法(bootstrapping)。可以做一个简单的估计,样本在m次采样中始终不被采到的概率是
(
1
−
1
m
)
m
(1 - \frac{1}{m})^m
(1−m1)m,取极限得到:
lim
m
→
∞
(
1
−
1
m
)
m
→
1
e
≈
0.368
\lim_{m→∞}(1 - \frac{1}{m})^m → \frac{1}{e} ≈ 0.368
m→∞lim(1−m1)m→e1≈0.368
即通过自主法采样,初始数据集中有约36.8%的样本未出现在采样数据集中,将这些未参与模型训练的数据称为袋外数据(包外估计,out-of-bag estimate)。
2.3 随机森林RandomForestClassifier
sklearn中随机森林的分类算法对应的是RandomForestClassifier。
class sklearn.ensemble.RandomForestClassifier(n_estimators=100, *, criterion='gini', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None, ccp_alpha=0.0, max_samples=None)1
关于参数的详细介绍也可在官网的论述中查看。从该RandomForestClassifier参数中我们可以看出,除了随机森林相关参数,其还包含了一般决策树的参数如:criterion,max_depth,max_features等参数,这些参数定义可参见上一篇的决策树博客,本节只选取一些与随机森林相关的关键参数简要说明如下:
n_estimators:森林中决策树的数量,默认100。 论上该数值是越大越好,但是随着决策树数量的增加,计算时间也会相应增长。所以,在实际应用中并不是取得越大就会越好,需结合实际问题和具体求解计算来选取合理的决策树个数。
bootstrap:是否进行bootstrap操作;布尔型(bool)变量,默认为True。如果bootstrap==True,将每次有放回地随机选取样本,只有在extra-trees中,bootstrap == False。
oob_score :即是否采用袋外样本来评估模型的好坏;布尔型(bool)变量,默认为False。一般建议设置为True,因为袋外分数反应了一个模型拟合后的泛化能力。
3. 实战 - 鸢尾花数据集随机森林分类
本小节所用实战数据同样为前面 Logistic回归章节博客用过的经典莺尾花数据集,具体的数据描述可参见前面博客,在此给出随机森林算法的实现。
前述可知,随机森林在每次划分时,选取单个或少量特征比多个特征得到的准确率要好,所以本实战示例中只选取2个特征来计算,易知总共有4*3/2=6种特征组合情况。
实战代码如下:
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
if __name__ == "__main__":
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
# 读取数据
path = 'iris.data'
data = pd.read_csv(path, header=None)
# 特征定义
iris_feature = '花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度'
# 数据处理:如果是字符型特征,则转换成数值型
x_prime = data[list(range(4))] # 数值型数据,无需额外转换操作
y = pd.Categorical(data[4]).codes # 字符型数据,需转换成数值型
# 拆分数据为训练集(70%)和测试集(30%)
x_prime_train, x_prime_test, y_train, y_test = train_test_split(x_prime, y, train_size=0.7, random_state=0)
# 特征组合
feature_pairs = [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]
plt.figure(figsize=(8, 6), facecolor='#FFFFFF')
for i, pair in enumerate(feature_pairs):
# 准备数据
x_train = x_prime_train[pair]
x_test = x_prime_test[pair]
# 随机森林 100棵树,用entropy衡量质量,最大深度6,使用OOB数据预测
model = RandomForestClassifier(n_estimators=100, criterion='entropy', max_depth=6, oob_score=True)
model.fit(x_train, y_train)
# 画图
N, M = 500, 500 # 横纵各采样多少个值
x1_min, x2_min = x_train.min()
x1_max, x2_max = x_train.max()
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) # 测试点
# 训练集上的预测结果
y_train_pred = model.predict(x_train)
acc_train = accuracy_score(y_train, y_train_pred)
y_test_pred = model.predict(x_test)
acc_test = accuracy_score(y_test, y_test_pred)
print('特征:', iris_feature[pair[0]], ' + ', iris_feature[pair[1]])
print('OOB Score:', model.oob_score_)
print('\t训练集准确率: %.4f%%' % (100*acc_train))
print('\t测试集准确率: %.4f%%\n' % (100*acc_test))
# 输出图形
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
y_hat = model.predict(x_show)
y_hat = y_hat.reshape(x1.shape)
plt.subplot(2, 3, i+1)
plt.contour(x1, x2, y_hat, colors='k', levels=[0, 1], antialiased=True, linestyles='--', linewidths=1)
plt.pcolormesh(x1, x2, y_hat, cmap=cm_light) # 预测值
plt.scatter(x_train[pair[0]], x_train[pair[1]], c=y_train, s=20, edgecolors='k', cmap=cm_dark, label='训练集')
plt.scatter(x_test[pair[0]], x_test[pair[1]], c=y_test, s=100, marker='*', edgecolors='k', cmap=cm_dark, label='测试集')
plt.xlabel(iris_feature[pair[0]], fontsize=12)
plt.ylabel(iris_feature[pair[1]], fontsize=12)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.grid(b=True, ls=':', color='#606060')
plt.suptitle('随机森林对鸢尾花数据两特征组合的分类结果', fontsize=15)
plt.tight_layout(1, rect=(0, 0, 1, 0.95)) # (left, bottom, right, top)
plt.show()
输出结果如下:
特征: 花萼长度 + 花萼宽度
OOB Score: 0.7333333333333333
训练集准确率: 89.5238%
测试集准确率: 64.4444%
特征: 花萼长度 + 花瓣长度
OOB Score: 0.9333333333333333
训练集准确率: 99.0476%
测试集准确率: 93.3333%
特征: 花萼长度 + 花瓣宽度
OOB Score: 0.9238095238095239
训练集准确率: 98.0952%
测试集准确率: 95.5556%
特征: 花萼宽度 + 花瓣长度
OOB Score: 0.9333333333333333
训练集准确率: 100.0000%
测试集准确率: 93.3333%
特征: 花萼宽度 + 花瓣宽度
OOB Score: 0.9047619047619048
训练集准确率: 98.0952%
测试集准确率: 91.1111%
特征: 花瓣长度 + 花瓣宽度
OOB Score: 0.9523809523809523
训练集准确率: 99.0476%
测试集准确率: 97.7778%
输出图形如下:
4.参考学习的书目及论文
- 机器学习算法视频 - 邹博
- 《机器学习实战》第7章 利用AdaBoost元算法提高分类性能
- 《机器学习之路》第2章 2.6 模型融合
- . 《机器学习 - 周志华》第8章 集成学习
- 《基于随机森林的视觉数据分类关键技术研究》 张乾 2016 博士论文 第5章 随机深度决策森林提升模型
- 《基于人类驾驶行为的无人驾驶车辆行为决策与运动规划方法研究》杜明博 2016 博士论文 第3章 无人驾驶车辆巧为决策方法研究
=文档信息=
本学习笔记由博主整理编辑,仅供非商用学习交流使用
由于水平有限,错误和纰漏之处在所难免,欢迎大家交流指正
如本文涉及侵权,请随时留言博主,必妥善处置
版权声明:非商用自由转载-保持署名-注明出处
署名(BY) :zhudj
文章出处:https://zhudj.blog.csdn.net/