1.2 泛化、过拟合与欠拟合( 三 )


构造随机森林
随机森林构造过程中包含两个随机的过程:随机选择样本(有放回)、随机选择特征(无放回)
随机选择样本:从n个数据点中有放回地(即同一样本可以多次被抽取)重复随机抽取一个样本,共抽取n次 。这样会创建一个与原数据集大小相同的数据集,但有些数据点会缺失(大约三分之一),而有些会重复 。比如:我们想要对列表['a', 'b', 'c', 'd']随机采样,可能出现['b', 'd', 'd', 'c'],或者['d', 'a', 'b' ,'d']等等 。
随机选择特征:在随机森林中,我们不像普通决策树一样计算所有特征的增益,而是从总量为M的特征向量中,随机选择m个特征,其中m可以等于sqrt(M),然后计算m个特征的增益,选择最优特征(属性)【注意,这里的随机选择特征是无放回的选择!】 。如果我们设置m等于sqrt(M),即考虑数据集所有的特征,那么随机森林中的书将会十分相似;相反,如果m等于1,只取一个特征,划分时将无法选择对哪个特征进行测试,只能对随机选择的某个特征搜索不同的阈值 。
由于随机森林采用了这两种随机采用,所构造的每棵决策树都是略有不同的 。由于随机选择特征,每棵树中的每次划分都是基于特征的不同子集 。
分析随机森林
下面我们将构造由5棵树组成的随机森林,代码如下:
from sklearn.datasets import make_moonsfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import train_test_splitfrom matplotlib import pylabfrom mglearn import plots, discrete_scatterX, y = make_moons(n_samples=100, noise=0.25, random_state=3)X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)forest = RandomForestClassifier(n_estimators=5, random_state=2)forest.fit(X_train, y_train)#画图fig, axes = pylab.subplots(2, 3, figsize=(20, 10))for i, (ax, tree) in enumerate(zip(axes.ravel(), forest.estimators_)):ax.set_title("Tree {}".format(i))plots.plot_tree_partition(X_train, y_train, tree, ax=ax)plots.plot_2d_separator(forest, X_train, fill=True, ax=axes[-1, -1], alpha=0.4)axes[-1, -1].set_title("Random Forest")discrete_scatter(X_train[:, 0], X_train[:, 1], y_train)
图:5棵随机化的决策树及其预测概率取平均后得到的?决策边界
图中5棵随机化的决策树都有误差,因为随机选择样本,导致一些训练点没有包含在这些树中,随机森林比单独每一棵树的过拟合倒要小,给出的决策边界也更准确 。在实际应用中,我们会用到更多的树,从而得到更平滑的边界 。
梯度提升回归树(梯度提升机)
梯度提升回归树是通过合并多个决策树来构建一个更为强大的模型,虽然名字中含有“回归”,但这个模型即可以用于回归,也可以用于分类 。与随机森林方法不同,梯度提升采用连续的方式构造树,每棵树都试图纠正前一棵树的错误 。默认情况下,梯度提升回归树没有随机化,而是用到了强预剪枝 。梯度提升树通常使用深度很小(1到5之间)的树,这样模型占用的内存更少,预测速度也更快 。
用-learn乳腺癌数据进行训练、拟合和测试集精度比较,代码如下,打印出结果分别为:
gbrt1:0.9655
gbrt2:0.9722
gbrt3:0.9722
from sklearn.ensemble import GradientBoostingClassifierfrom sklearn.datasets import load_breast_cancerfrom sklearn.model_selection import train_test_splitcancer = load_breast_cancer()X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)#默认最大深度是3gbrt1 = GradientBoostingClassifier(random_state=0)gbrt1.fit(X_train, y_train)#设置最大深度为1gbrt2 = GradientBoostingClassifier(random_state=0, max_depth=1)gbrt2.fit(X_train, y_train)#设置最大深度为2gbrt3 = GradientBoostingClassifier(random_state=0, max_depth=2)gbrt3.fit(X_train, y_train)print('Accuracy gbrt1:{}'.format(gbrt1.score(X_test, y_test)))print('Accuracy gbrt2:{}'.format(gbrt2.score(X_test, y_test)))print('Accuracy gbrt3:{}'.format(gbrt3.score(X_test, y_test)))