chapter6 Decision Trees(决策树)

和SVM一样, 决策树是一种多功能机器学习算法, 即可以执行分类任务也可以执行回归任务, 甚至包括多输出(multioutput)任务。

它是一种功能很强大的算法,可以对很复杂的数据集进行拟合。例如,在第二章中对加利福尼亚住房数据集使用决策树回归模型进行训练,就很好的拟合了数据集(实际上是过拟合)。

决策树也是随机森林的基本组成部分(见第7章),而随机森林是当今最强大的机器学习算法之一

在本章中,将首先讨论如何使用决策树进行训练,可视化和预测。

然后会学习在 Scikit-learn 上面使用 CART 算法,并且探讨如何调整决策树让它可以用于执行回归任务。

最后,讨论一下决策树目前存在的一些局限性。

设置

from __future__ import division,print_function,unicode_literals

import numpy as np
np.random.seed(42)

%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12

import os
PROJECT_ROOT_DIR = "."
CHAPTER_ID = "decision_trees"
def image_path(fig_id):
    return os.join.path(PROJECT_ROOT_DIR,"images",CHAPTER_ID,fig_id)
def save_fig(fig_id,tight_layout = True):
    print("Saving figure",fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(image_path(fig_id) + ".png",format = 'png',dpi = 300)

import warnings
warnings.filterwarnings(action = "ignore",module = "scipy",message = "^interal gelsd")

决策树的训练和可视化

为了理解决策树,先构建一个决策树并亲身体验它到底如何进行预测。

接下来的代码就是在鸢尾花数据集上进行一个决策树分类器的训练。

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
iris = load_iris()
X = iris.data[:, 2:] 
y = iris.target
tree_clf = DecisionTreeClassifier(max_depth=2,random_state = 42)
tree_clf.fit(X, y)

可以通过使用export_graphviz()方法,通过生成一个叫做iris_tree.dot的图形定义文件将一个训练好的决策树模型可视化。

from sklearn.tree import export_graphviz
export_graphviz(
                tree_clf,
                out_file = image_path("iris_tree.dot"),
                feature_names = iris.feature_names[2:],
                class_names = iris.target_names,
                rounded = True,
                filled = True)

然后,可以利用graphviz package[1] 中的dot命令行,将.dot文件转换成 PDF 或 PNG 等多种数据格式。例如,使用命令行将.dot文件转换成.png文件的命令如下:

[1] Graphviz是一款开源图形可视化软件包,http://www.graphviz.org/

$ dot -Tpng iris_tree.dot -o iris_tree.png

第一个决策树如图 6-1。

图6-1. 鸢尾花决策树

开始预测

现在来看看在图 6-1 中的树是如何进行预测的。

决策树的众多特性之一就是, 它不需要太多的数据预处理, 尤其是不需要进行特征的缩放或者归一化。

节点的samples属性统计出它应用于多少个训练样本实例。

例如,有100个训练实例是花瓣长度大于 2.45 里面的(深度为 1, 右侧),在这 100 个样例中又有 54 个花瓣宽度小于 1.75cm(深度为 2,左侧)。

节点的value属性告诉你这个节点对于每一个类别的样例有多少个。

例如:右下角的节点中包含 0 个 Iris-Setosa,1 个 Iris-Versicolor 和 45 个 Iris-Virginica。

节点的Gini属性用于测量它的纯度:如果一个节点包含的所有训练样例全都是同一类别的,就说这个节点是纯的(Gini=0)。

例如,深度为 1 的左侧节点只包含 Iris-Setosa 训练实例,它就是一个纯节点,Gini 指数为 0。

公式 6-1 显示了训练算法如何计算第i个节点的 gini 分数 。例如, 深度为 2 的左侧节点基尼指数为:。另外一个纯度指数也将在后文很快提到。

公式6-1. Gini分数

  • 是第i个节点中训练实例为的k类实例的比例

Scikit-Learn 用的是 CART 算法, CART 算法仅产生二叉树。

决策树的决策边界

from matplotlib.colors import ListedColormap

def plot_decision_boundry(clf,X,y,axes = [0,7.5,0,3],iris = True,legend = False,plot_training = True):
    x1s = np.linspace(axes[0],axes[1],100)
    x2s = np.linspace(axes[2],axes[3],100)
    x1,x2 = np.meshgrid(x1s,x2s)
    X_new = np.c_[x1.ravel(),x2.ravel()]
    y_pred = clf.predict(X_new).reshape(x1.shape)
    
    custom_cmap = ListedColormap('#fafab0','#9898ff','#a0faa0')
    plt.contourf(x1,x2,y_pred,alpha = 0.3,cmap = custom_cmap)

    if not iris:
        custom_cmap2 = ListedColormap(['#7d7d58','#4c4c7f','#507d50'])
        plt.contourf(x1,x2,y_pred,alpha = 0.8,cmap = custom_cmap2)

    if plot_training:
        plt.plot(X[:,0][y == 0],X[:,1][y == 0],"yo",label = "Iris-Setosa")
        plt.plot(X[:,0][y == 1],X[:,1][y == 1],"bs",label = "Iris-Versicolor")
        plt.plot(X[:,0][y == 2],X[:,1][y == 2],"g^",label = "Iris-Virginica")
        plt.axis(axes)

    if iris:
        plt.xlabel("Petal length",fontsize = 14)
        plt.ylabel("Petal width",fontsize = 14)
    else:
        plt.xlabel(r"$x_1$",fontsize = 18)
        plt.ylabel(r"$x_2$",fontsize = 18,rotation = 0)
    
    if legend:
        plt.legend(loc = "lower right",fontsize = 14)


plt.figure(figsize = (8,4))
plot_decision_boundary(tree_clf,X,y)
plt.plot([2.45,2.45],[0,3],"k-",linewidth = 2)
plt.plot([2.45,7.5],[1.75,1.75],"k--",linewidth = 2)
plt.plot([4.95,4.95],[0,1.75],"k:",linewidth = 2)
plt.plot([4.85,4.85],[1.75,3],"k:",linewidth = 2)
plt.text(1.40,1.0,"Depth = 0",fontsize = 15)
plt.text(3.2,1.80,"Depth = 1",fontsize = 13)
plt.text(4.05,0.5,"(Depth = 2)",fontsize = 11)
save_fig("decision_tree_decision_boundaries_plot")
plt.show()

图 6-2(上图)显示了决策树的决策边界。粗的垂直线代表根节点(深度为 0)的决策边界:花瓣长度为 2.45 厘米。由于左侧区域是纯的(只有 Iris-Setosa),所以不能再进一步分裂。然而,右边的区域是不纯的,所以深度为 1 的右边节点在花瓣宽度为 1.75 厘米处分裂(用虚线表示)。又由于max_depth设置为 2,决策树在那里停了下来。但是,如果将max_depth设置为 3,两个深度为 2 的节点,每个都将会添加另一个决策边界(用虚线表示)。

 

模型小知识:白盒与黑盒

正如我们看到的一样,决策树非常直观,它的决策很容易解释。这种模型通常被称为白盒模型。相反,随机森林或神经网络通常被认为是黑盒模型。他们能做出很好的预测,并且可以轻松检查它们做出这些预测过程中计算的执行过程。然而,人们通常很难用简单的术语来解释为什么模型会做出这样的预测。例如,如果一个神经网络说一个特定的人出现在图片上,我们很难知道究竟是什么导致了这一个预测的出现:

估计分类概率

决策树还可以估计某个实例属于特定类k的概率:首先遍历树来查找此实例的叶节点,然后它返回此节点中类k的训练实例的比例。

例如,一个花瓣长 5 厘米,宽 1.5 厘米的花朵。相应的叶节点是深度为 2 的左节点,因此决策树应该输出以下概率:Iris-Setosa 为 0%(0/54),Iris-Versicolor 为 90.7%(49/54),Iris-Virginica 为 9.3%(5/54)。当然,如果要求它预测具体的类,它应该输出 Iris-Versicolor(类别 1),因为它具有最高的概率。

测试一下:

tree_clf.predict_proba([[5, 1.5]])

tree_clf.predict([[5, 1.5]])

完美!

CART 训练算法

Scikit-Learn 用分类回归树(Classification And Regression Tree,简称 CART)算法训练决策树(也叫“增长树”)。这种算法思想真的非常简单:

首先使用单个特征k和阈值 (例如,“花瓣长度≤2.45cm”)将训练集分成两个子集。它如何选择k和阈值呢?它寻找一对 ,能够产生最纯粹的子集(通过子集大小加权计算)。算法尝试最小化的损失函数,如公式 6-2所示。

公式6-2. CART进行分类的损失函数

当它成功的将训练集分成两部分之后, 它将会继续使用相同的递归式逻辑继续的分割子集,然后是子集的子集。当达到预定的最大深度之后将会停止分裂(由max_depth超参数决定),或者是它找不到可以继续降低不纯度的分裂方法的时候。几个其他超参数(之后介绍)控制了其他的停止生长条件(min_samples_splitmin_samples_leafmin_weight_fraction_leafmax_leaf_nodes)。

警告
正如所见,CART 算法是一种贪婪算法,贪婪算法通常会产生一个相当好的解决方法,但它不保证这是全局中的最佳解决方案。

不幸的是,找到最优树是一个 NP 完全问题:它需要 时间,即使对于相当小的训练集也会使问题变得棘手。 这就是为什么必须设置一个“合理的”(而不是最佳的)解决方案。

计算复杂度

在建立好决策树模型后, 做出预测需要遍历决策树, 从根节点一直到叶节点。决策树通常近似左右平衡,因此遍历决策树需要经历大致 个节点。由于每个节点只需要检查一个特征的值,因此总体预测复杂度仅为 与特征的数量无关。 所以即使在处理大型训练集时,预测速度也非常快。

然而,训练算法的时候(训练和预测不同)需要比较所有特征(如果设置了max_features会更少一些)。这就使得训练复杂度为 。对于小训练集(少于几千例),Scikit-Learn 可以通过预先设置数据(presort = True)来加速训练,但是这对于较大训练集来说会显着减慢训练速度。

Gini不纯度或信息熵

通常,算法使用 Gini 不纯度来进行检测, 但是也可以通过将标准超参数设置为"entropy"来使用熵不纯度进行检测。

在机器学习中,熵经常被用作不纯度的衡量方式,当一个集合内只包含一类实例时, 我们称为数据集的熵为 0。

公式 6-3 显示了第i个节点的熵的定义,例如,在图 6-1 中, 深度为 2 左节点的熵为

公式6-3. 熵

那么到底应该使用 Gini 指数还是熵呢? 事实上大部分情况都没有多大的差别:它们会生成类似的决策树。基尼指数计算稍微快一点,所以这是一个很好的默认值。但是,也有的时候它们会产生不同的树,基尼指数会趋于在树的分支中将最多的类隔离出来,而熵指数趋向于产生略微平衡一些的决策树模型。

正则化超参数

决策树几乎不对训练数据做任何假设(与此相反的是线性回归等模型,这类模型通常会假设数据是符合线性关系的)。

如果不添加约束,树结构模型通常将根据训练数据调整自己,使自身能够很好的拟合数据,而这种情况下大多数会导致模型过拟合。

这一类的模型通常会被称为非参数模型,这不是因为它没有任何参数(通常也有很多),而是因为在训练之前没有确定参数的具体数量,所以模型结构可以根据数据的特性自由生长。

与此相反的是,像线性回归这样的参数模型有事先设定好的参数数量,所以自由度是受限的,这就减少了过拟合的风险(但是增加了欠拟合的风险)。

DecisionTreeClassifier类还有一些其他的参数用于限制树模型的形状: min_samples_split(节点在被分裂之前必须具有的最小样本数),min_samples_leaf(叶节点必须具有的最小样本数),min_weight_fraction_leaf(和min_samples_leaf相同,但表示为加权总数的一小部分实例),max_leaf_nodes(叶节点的最大数量)max_features(在每个节点被评估是否分裂的时候,具有的最大特征数量)。增加min_* hyperparameters或者减少max_* hyperparameters会使模型正则化。

使用min_samples_leaf正则化

from sklearn.datasets import make_moons
Xm,ym = make_moons(n_samples = 100,noise = 0.25,random_state = 53)

deep_tree_clf1 = DecisionTreeClassifier(random_state = 42)
deep_tree_clf2 = DecisionTreeClassifier(min_samples_leaf = 4,random_state = 42)
deep_tree_clf1.fit(Xm,ym)
deep_tree_clf2.fit(Xm,ym)

plt.figure(figsize = (11,4))
plt.subplot(121)
plot_decision_boundary(deep_tree_clf1,Xm,ym,axes = [-1.5,2.5,-1,1.5],iris = False)
plt.title("No restrictions",fontsize = 16)
plt.subplot(122)
plot_decision_boundary(deep_tree_clf2,Xm,ym,axes = [-1.5,2.5,-1,1.5],iris = False)
plt.title("min_samples_leaf = {}".format(deep_tree_clf2.min_samples_leaf),fontsize = 14)
save_fig("min_samples_leaf_plot")
plt.show()


图 6-3(上图) 显示了对moons数据集(在第 5 章介绍过)进行训练生成的两个决策树模型,左侧的图形对应的决策树使用默认超参数生成(没有限制生长条件),右边的决策树模型设置为min_samples_leaf=4。很明显,左边的模型过拟合了,而右边的模型泛用性更好。

回归

决策树也能够执行回归任务,使用 Scikit-Learn 的DecisionTreeRegressor类构建一个回归树,用max_depth = 2在具有噪声的二次项数据集上进行训练。

np.random.seed(42)
m = 200
X = np.random.rand(m,1)
y = 4 * (X - 0.5) ** 2
y = y + np.random.randn(m,1) / 10

from sklearn.tree import DecisionTreeRegressor
tree_reg = DecisionTreeRegressor(max_depth=2,random_state = 42)
tree_reg.fit(X, y)

结果如图 6-4 所示

图6-4. 用决策树进行回归

这棵树看起来非常类似于你之前建立的分类树,它的主要区别在于,它不是预测每个节点中的样本所属的分类,而是预测一个具体的数值。例如,假设想对 的新实例进行预测。从根开始遍历树,最终到达预测值等于 0.1106 的叶节点。该预测仅仅是与该叶节点相关的 110 个训练实例的平均目标值。而这个预测结果在对应的 110 个实例上的均方误差(MSE)等于 0.0151。

两个决策树回归模型的预测

from sklearn.tree import DecisionTreeRegressor
tree_reg1 = DecisionTreeRegressor(random_state = 42,max_depth = 2)
tree_reg2 = DecisionTreeRegressor(max_depth = 3,random_state = 42)
tree_reg1.fit(X,y)
tree_reg2.fit(X,y)

def plot_regression_predictions(tree_reg,X,y,axes = [0,1,-0.2,1],ylabel = "$y$"):
    x1 = np.linspace(axes[0],axes[1],500).reshape(-1,1)
    y_pred = tree_reg.predict(x1)
    
    plt.axis(axes)
    plt.xlabel(r"$x_1$",fontsize = 18)
    if ylabel:
        plt.ylabel(ylabel,fontsize = 18,rotation = 0)
    
    plt.plot(X,y,"b.")
    plt.plot(x1,y_pred,"r.-",linewidth = 2,label = r"$\hat{y}$")

    
plt.figure(figsize = (11,4))
plt.subplot(121)
plot_regression_predictions(tree_reg1,X,y)
for split,style in ((0.1973,"k-"),(0.0917,"k--"),(0.7718,"k--")):
    plt.plot([split,split],[-0.2,1],style,linewidth = 2)
plt.text(0.21,0.65,"Depth = 0",fontsize = 15)
plt.text(0.01,0.2,"Depth = 1",fontsize = 13)
plt.text(0.65,0.8,"Depth = 1",fontsize = 13)
plt.legend(loc = "upper center",fontsize = 18)
plt.title("max_depth = 2",fontsize = 14)

plt.subplot(122)
plot_regression_predictions(tree_reg2,X,y,ylabel = None)
for split,style in ((0.1973,"k-"),(0.0917,"k--"),(0.7718,"k--")):
    plt.plot([split,split],[-0.2,1],style,linewidth = 2)
for split in (0.0458,0.1298,0.2873,0.9040):
    plt.plot([split,split],[-0.2,1],"k:",linewidth = 1)
plt.text(0.3,0.5,"Depth = 2",fontsize = 13)
plt.title("max_depth = 3",fontsize = 14)

save_fig("tree_regression_plot")
plt.show()

在图 6-5 (上图)的左侧显示的是模型的预测结果,如果将max_depth=3设置为 3,模型就会如 6-5 图(上图)右侧显示的那样。注意每个区域的预测值总是该区域中实例的平均目标值。算法以一种使大多数训练实例尽可能接近该预测值的方式分割每个区域。

图里面的红线就是训练实例的平均目标值,对应上图中的value

 

CART 算法的工作方式与之前处理分类模型基本一样,不同之处在于,现在不再以最小化不纯度的方式分割训练集,而是试图以最小化 MSE 的方式分割训练集。

公式 6-4 显示了该算法试图最小化的损失函数。

和处理分类任务时一样,决策树在处理回归问题的时候也容易过拟合。如果不添加任何正则化(默认的超参数),得到的图形就会过拟合。

正则化一个决策树回归器

export_graphviz(
                tree_reg1,
                out_file = image_path("regression_tree.dot"),
                feature_names = ["x1"],
                rounded = True,
                filled = True)


tree_reg1 = DecisionTreeRegressor(random_state = 42)
tree_reg2 = DecisionTreeRegressor(min_samples_leaf = 10,random_state = 42)
tree_reg1.fit(X,y)
tree_reg2.fit(X,y)

x1 = np.linspace(0,1,500).reshape(-1,1)
y_pred1 = tree_reg1.predict(x1)
y_pred2 = tree_reg2.predict(x1)


plt.subplot(121)
plt.plot(X, y, "b.")
plt.plot(x1, y_pred1, "r.-", linewidth=2, label=r"$\hat{y}$")
plt.axis([0, 1, -0.2, 1.1])
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", fontsize=18, rotation=0)
plt.legend(loc="upper center", fontsize=18)
plt.title("No restrictions", fontsize=14)
    
plt.subplot(122)
plt.plot(X, y, "b.")
plt.plot(x1, y_pred2, "r.-", linewidth=2, label=r"$\hat{y}$")
plt.axis([0, 1, -0.2, 1.1])
plt.xlabel("$x_1$", fontsize=18)
plt.title("min_samples_leaf = {}".format(tree_reg2.min_samples_leaf), fontsize=14)
save_fig("tree_regression_regularization_plot")
plt.show()

图 6-6(上图)左侧的预测结果,显然,过度拟合的程度非常严重。设置了min_samples_leaf = 10,相对就会产生一个更加合适的模型了,就如图 6-6 (上图)右侧所示的那样。

 

不稳定性

决策树很容易理解和解释,易于使用且功能丰富而强大。然而,它也有一些限制,首先,决策树很喜欢设定正交化的决策边界,(所有边界都是和某一个轴相垂直的),这使得它对训练数据集的旋转很敏感。
对训练集数据旋转的敏感性

np.random.seed(6)
Xs = np.random.rand(100,2) - 0.5
ys = (Xs[:,0] > 0).astype(np.float32) * 2

angle = np.pi / 4
rotation_matrix = np.array([np.cos(angle),-np.sin(angle)],[np.sin(angle),np.cos(angle)])
Xsr = Xs.dot(rotation_matrix)

tree_clf_s = DecisionTreeClassifier(random_state = 42)
tree_clf_sr = DecisionTreeClassifier(random_state = 42)
tree_clf_s.fit(Xs,ys)
tree_clf_sr.fit(Xsr,ys)

plt.figure(figsize = (11,4))
plt.subplot(121)
plot_decision_boundary(tree_clf_s,Xs,ys,axes = [-0.7,0.7,-0.7,0.7],iris = False)
plt.subplot(122)
plot_decision_boundary(tree_clf_sr,Xsr,ys,axes = [-0.7,0.7,-0.7,0.7],iris = False)

save_fig("sensitivity_to_rotation_plot")
plt.show()

图 6-7(上图)显示了一个简单的线性可分数据集。在左图中,决策树可以轻易的将数据分隔开,但是在右图中,当把数据旋转了 45° 之后,决策树的边界看起来变的格外复杂。尽管两个决策树都完美的拟合了训练数据,右边模型的泛化能力很可能非常差。 解决这个难题的一种方式是使用 PCA 主成分分析(第八章),这样通常能使训练结果变得更好一些。

angle = np.pi / 180 * 20
rotation_matrix = np.array([np.cos(angle),-np.sin(angle)],[np.sin(angle),np.cos(angle)])
Xr = X.dot(rotation_matrix)

tree_clf_r = DecisionTreeClassifier(random_state = 42)
tree_clf_r.fit(Xr,y)

plt.figure(figsize = (8,3))
plot_decision_boundary(tree_clf_r,Xr,y,axes = [0.5,7.5,-1.0,1],iris = False)
plt.show()

 

更加通俗的讲,决策时的主要问题是它对训练数据的微小变化非常敏感,举例来说,仅仅从鸢尾花训练数据中将最宽的 Iris-Versicolor 拿掉(花瓣长 4.8 厘米,宽 1.8 厘米),然后重新训练决策树模型,

对训练集细节的敏感性

X[X[:,1] == X[:,1][y == 1].max & (y == 1)]

not_widest_versicolor = (X[:,1] != 1.8) | (y == 2)
X_tweaked = X[not_widest_versicolor]
y_tweaked = y[not_widest_versicolor]

tree_clf_tweaked = DecisionTreeClassifier(max_depth = 2,random_state = 40)
tree_clf_tweaked.fit(X_tweaked,y_tweaked)

plt.figure(figsize = (8,4))
plot_decision_boundary(tree_clf_tweaked,X_tweaked,y_tweaked,legend = False)
plt.plot([0,7.5],[0.8,0.8],"k-",linewidth = 2)
plt.plot([0,7.5],[1.75,1.75],"k--",linewidth = 2)
plt.text(1.0,0.9,"Depth = 0",fontsize = 15)
plt.text(1.0,1.80,"Depth = 1",fontsize = 13)
save_fig("decision_tree_instability_plot")
plt.show()

得到图 6-8(上图)中的模型。决策树有了非常大的变化(相比原来的图 6-2),事实上,由于 Scikit-Learn 的训练算法是非常随机的,即使是相同的训练数据你也可能得到差别很大的模型(除非设置了随机数种子)。

在下一章中将会看到,随机森林可以通过多棵树的平均预测值限制这种不稳定性。

练习

7. 对moons数据集进行决策树训练并优化模型。

通过语句make_moons(n_samples=10000, noise=0.4)生成moons数据集

from sklearn.datasets import make_moons
X, y = make_moons(n_samples=10000, noise=0.4, random_state=42)

通过train_test_split()将数据集分割为训练集和测试集。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

进行交叉验证,并使用网格搜索法寻找最好的超参数值。(提示: 尝试各种各样的max_leaf_nodes值)

from sklearn.model_selection import GridSearchCV
params = {'max_leaf_nodes': list(range(2,100)),'min_samples_split': [2,3,4]}
grid_search_cv = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1, verbose=1)
grid_search_cv.fit(X_train,y_train)

使用这些超参数训练全部的训练集数据,并在测试集上测量模型的表现。

grid_search_cv.best_estimator_

from sklearn.metrics import accuracy_score
y_pred = grid_search_cv.predict(X_test)
accuracy_score(y_test,y_pred)

8. 生成森林

接着前边的练习,现在,生成 1000 个训练集的子集,每个子集包含 100 个随机选择的实例。(提示:可以使用 Scikit-Learn 的ShuffleSplit类。)

from sklearn.model_selection import ShuffleSplit
n_trees = 1000
n_instances = 100
mini_sets = []

rs = ShuffleSplit(n_split = n_trees,test_size = len(X_train) - n_instances,random_state = 42)

for mini_train_index,mini_test_index in rs.split(X_train):
    X_mini_train = X_train[mini_train_index]
    y_mini_train = y_train[mini_train_index]
    mini_sets.append((X_mini_train,,y_mini_train))

使用上面找到的最佳超参数值,在每个子集上训练一个决策树。在测试集上测试这 1000 个决策树。

from sklearn.base import clone
forest = [clone(grid_search_cv.best_estimator_) for _ in range(n_trees)]

accuracy_scores = []

for tree, (X_mini_train, y_mini_train) in zip(forest, mini_sets):
    tree.fit(X_mini_train, y_mini_train)
    y_pred = tree.predict(X_test)
    accuracy_scores.append(accuracy_score(y_test, y_pred))

np.mean(accuracy_scores)

由于它们是在较小的集合上进行了训练,因此这些决策树比第一个决策树效果更差,只能达到约 80% 的准确度。

对于每个测试集实例,生成 1000 个决策树的预测结果,然后只保留出现次数最多的预测结果(使用 SciPy 的mode()函数)。这个函数可以对测试集进行多数投票预测。

Y_pred = np.empty([n_trees, len(X_test)], dtype=np.uint8)
for tree_index, tree in enumerate(forest):
    Y_pred[tree_index] = tree.predict(X_test)

from scipy.stats import mode
y_pred_majority_votes, n_votes = mode(Y_pred, axis=0)

在测试集上评估这些预测结果

accuracy_score(y_test, y_pred_majority_votes.reshape([-1]))

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值