目录
误差:
- 偏差:欠拟合(Underfitting)
- 方差:过拟合(Overfitting)
因为偏差的符号有正有负,所以若干弱模型的偏差平均可以使结果偏差从各自较高的绝对值降低到最小的程度;而对于方差来说,弱模型的方差本就不高,在综合求平均后仍能维持在较低的水平。因此集成学习达到了能自动找到最优错误偏差和方差的效果,这对于之前的强模型来说需要数据研究者反复地调试超参数才能获得。
关键:开发出一种可以生成大量近似独立的模型的方法,然后把它们集成起来
层次架构:
-
基学习器:单个机器学习算法。(支持向量机(SVM)、线性回归、k最近邻、二元决策树…)
-
上层算法:对这些基学习器做巧妙的处理,使其模型近似相对独立。(投票(Bagging)、提升(Boosting)、随机森林(Random forests)…)
1 二元决策树
基于属性做一系列的二元(是/否)决策。每次决策对应于从两种可能性中选择一个。每次决策后,要么引出另外一个决策,要么生成最终的结果。
DecisionTreeRegressor
DecisionTreeRegressor(ccp_alpha=0.0, criterion='mse', max_depth=None,
max_features=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort='deprecated',
random_state=None, splitter='best')
模型参数:
- criterion:取值gini或entropy,即使用基尼指数还是熵计算信息增益。
- max_depth:树的最大深度。
- min_samples_split:继续分裂一个结点最少需要的训练样本数。
- min_samples_leaf:叶子结点最少含有的训练样本数。
- max_leaf_nodes:叶子结点的最大总数。
- min_impurity_decrease:用于计算叶子结点的最小纯度(即不同目标值样本之间的比值)。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import tree
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
plt.rcParams['font.sans-serif'] = ['SimHei'] # 换sans-serif字体
plt.rcParams['axes.unicode_minus'] = False # 解决坐标轴负数的负号显示问题
%matplotlib inline
# 生成数据集
nPoints = 100
# 产生一组含标准正态随机扰动数据集
x = 1.0*np.arange(nPoints+1)/nPoints - 0.5
np.random.seed(1)
y = x + np.random.normal(scale=0.1,size=nPoints+1)
plt.plot(x,y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
# 训练1层决策树
simpleTree = DecisionTreeRegressor(max_depth=1)
simpleTree.fit(x.reshape((nPoints+1,1)), y)
with open("simpleTree.dot", 'w') as f:
f = tree.export_graphviz(simpleTree, out_file=f)
# 根据1层决策树预测并绘图比较
yHat = simpleTree.predict(x.reshape((nPoints+1,1)))
plt.figure()
plt.plot(x, y, label=u'真值 y')
plt.plot(x, yHat, label=u'树预测', linestyle='--')
plt.legend(bbox_to_anchor=(1,0.2))
plt.xlabel('x')
plt.ylabel('y')
plt.show()
# 转换成图片
# !dot -Tpng simpleTree.dot -o simpleTree.png
# 从图片中读取
# plt.figure(figsize=(5, 5))
# img=plt.imread("simpleTree.png")
# plt.imshow(img)
# plt.axis('off')
# plt.show()
# 训练2层决策树
simpleTree2 = DecisionTreeRegressor(max_depth=2)
simpleTree2.fit(x.reshape((nPoints+1,1)), y)
# 根据2层决策树预测并绘图比较
yHat = simpleTree2.predict(x.reshape((nPoints+1,1)))
plt.figure()
plt.plot(x, y, label=u'真值 y')
plt.plot(x, yHat, label=u'树预测', linestyle='--')
plt.legend(bbox_to_anchor=(1,0.2))
plt.xlabel('x')
plt.ylabel('y')
plt.show()
2 自举集成(Bagging)
步骤:
- 从训练集中通过有放回均匀随机抽样获得N组Bootstrap样本集。
- 每组Bootstrap样本集按预先选定的某个基学习器构建模型,一共构建N个模型。
- 通过投票或取平均来整合这N个模型的预测值,进而获得整个集成模型的预测值。
有放回均匀随机抽样意味着:
- Bootstrap样本集可能有重复样本;
- 这N组Bootstrap样本集的并集可能会遗漏掉原始数据。
在整体样本数量足够多的情况下,通过bootstrap采样到的子集只有期望约为63.2%的无重复样本。因为bootstrap能够生成与训练样本整体不同的数据分布,这样等于扩充了训练样本空间,这为集成模型中各模型带来多样性。所以通过bootstrap采样能够训练出适应性更强的模型。
一般机器学习模型的评估需要通过与训练集相互独立的另一个测试集来完成。而Bagging Method类模型在训练过程中划分不同独立数据子集的行为在侧面引入了另一个好处,就是可以使用训练数据本身进行模型准确率的评估。这就是 Out-of-Bag Estimation(简称 OOB),它是指基模型的评估预测只采用未参与到其本身训练的数据集。因此虽然整体上没有给出独立的测试集,但每个基模型使用的训练数据和预测数据是完全隔离的
sklearn
BaggingRegressor(base_estimator=None, bootstrap=True, bootstrap_features=False,
max_features=1.0, max_samples=1.0, n_estimators=100,
n_jobs=None, oob_score=False, random_state=1, verbose=0,
warm_start=False)
- base_estimator
None是DecisionTree,Object可以指定基估计器(base estimator)。
- n_estimators
要集成的基估计器的个数。
- max_samples(int or float)
决定从X_train抽取去训练基估计器的样本数量。int 代表抽取数量,float代表抽取比例
- max_features
决定从x_train抽取去训练基估计器的特征数量。int 代表抽取数量,float代表抽取比例
- bootstrap
决定样本子集的抽样方式(有放回和不放回)
- bootstrap_features
决定特征子集的抽样方式(有放回和不放回)
- oob_score
决定是否使用包外估计(out of bag estimate)泛化误差
- warm_start
若设为True则可以再次使用训练好的模型并向其中添加更多的基学习器
- n_jobs
并行运行的作业数
- verbose : int, optional (default=0)
属性介绍:
- oob_score_
使用包外估计这个训练数据集的得分
- oob_prediction_
在训练集上用out-of-bag估计计算的预测.如果n_estimator很小,则可能在抽样过程中数据点不会被忽略。在这种情况下,oob_prediction_可能包含NaN。
选择二元决策树作为基学习器, 最后取平均来整合各模型的预测结果。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import tree
from sklearn.tree import DecisionTreeRegressor
# 生成数据集
np.random.seed(1)
nPoints = 1000
# 产生一组含标准正态随机扰动数据集
X = 1.0*np.arange(nPoints)/(nPoints) - 0.5
y = X + np.random.normal(scale=0.1,size=nPoints)
X = X.reshape(-1,1)
y = y.reshape(-1,1)
plt.plot(X,y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
# 划分数据集,测试集30%
nSample = int(nPoints*0.30)
idxTest = np.random.choice(nPoints,nSample,replace=False)
# 注意排序
idxTest.sort()
idxTrain = [idx for idx in range(nPoints) if not(idx in idxTest)]
X_train = X[idxTrain]
y_train = y[idxTrain]
X_test = X[idxTest]
y_test = y[idxTest]
通过训练集生成大量近似独立的模型
def bagging_train(numTreesMax = 20,treeDepth = 1):
"""
numTreesMax:生成的最大模型数
treeDepth:决策树深度
"""
# 收集模型及其对应的预测
modelList = []
predList = []
# 用于随机提升(bagging)的样本数
nBagSamples = int(len(X_train) * 0.5)
for iTrees in range(numTreesMax):
# 有放回均匀取样 replace默认为True
idxBag = np.random.choice(nPoints-nSample