Press "Enter" to skip to content

技术专栏丨深入解释决策树回归器

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

无论是在Kaggle这类竞赛中,还是商业环境,决策树回归器都已经是最常用的机器学习算法之一。决策树可用于分类和回归问题。本文介绍了决策树回归器算法以及一些高级话题。

 

 

重要术语

 

它是如何工作的?

 

如何为决策树拆分决策?

 

问答

 

什幺时候不用?

 

优点和缺点

 

避免过度拟合的技巧

 

决策树与随机森林

 

Sklearn决策树的超参数

 

基于树的模型VS线性模型

 

决策树模型的可视化

 

结论

 

参考

 

 

Photo by Todd Quackenbush / Unsplash-

 

决策树可以用以下要点概括:

 

决策树是使用一组二进制规则来计算目标值的预测模型

 

每个个体树都是一个简单的模型,有分支,节点和叶子

 

重要术语

 

在深入研究之前,让我们看一下决策树的基本术语:

 

根节点: 它代表整个总体或样本,并进一步拆分为两个或更多个同类集。

 

拆分:将节点划分为两个或更多个子节点的过程。

 

决策节点:当子节点分裂成更多的子节点时,它被称为决策节点。

 

叶子/终端节点:不拆分的节点称为叶子或终端节点。

 

剪枝:删除决策节点的子节点,此过程称为剪枝。可以认为是拆分的反过程。

 

分支/子树:整个树的子部分称为分支或子树。

 

父节点和子节点:划分出子节点的节点称为子节点的父节点,而子节点是父节点的子节点。

 

 

它是如何工作的?

 

决策树通过向数据提出一系列问题来实现估计值,每个问题都会缩小可能值的范围,直到模型足够自信地进行单个预测。问题的顺序及其内容由模型决定。此外,提出的问题都是真/假的形式。

 

这有点难以掌握,因为它不是人类自然思考的方式,也许显示这种差异的最好方法是创建一个真正的决策树。在上述问题中X1,X2是两个特征,它们允许我们通过询问真/假来对目标变量y进行预测。

 

 

对于每个真/假的答案,都有单独的分支。无论问题的答案如何,我们最终都会实现一个预测(叶节点)。从顶部的根节点开始,然后在树中继续回答问题。所以给出任何一对X1,X2。

 

我应该提到的决策树的一个方面是它实际是如何学习的(如何形成’问题’以及如何设置阈值)。作为监督机器学习模型,决策树学习将数据映射到训练模型构建的输出上。

 

在训练期间,模型将拟合任何与问题域相关的历史数据,以及我们希望模型预测的真实值。该模型将学习数据和目标变量之间的关系。

 

在训练阶段之后,决策树产生类似于上图所示的树,计算最佳问题以及要求的顺序,以便能够进行最准确的估计。当我们想要进行预测时,应该向模型提供相同的数据格式。预测将是基于训练过的训练数据集产生估计值。

 

如何为决策树拆分决策

 

制定拆分的策略会严重影响树的准确性。对分类和回归树来说决策标准不同。决策树回归器通常使用均方误差(MSE)来决定将节点分成两个或更多个子节点。

 

假设我们正在做二叉树,算法首先会选择一个值,然后将数据拆分为两个子集。对于每个子集,它将分别计算MSE。树将会选择具有最小MSE值的结果的值。

 

让我们来看一下Splitting如何决定决策树回归器的更多细节。创建树的第一步是创建第一个二元决策。你打算怎幺做?

 

我们需要选择一个变量和要拆分的值,以使两个组尽可能彼此不同。

 

对于每个变量,对于该变量的可能值的每个可能值,查看哪个更好。

 

如何判断它是否更好?取两个新节点的加权平均值(mse * num_samples)。

 

那幺我们现在有:

 

一个表示拆分的效果的数字,是两组创建的平均平方误差的加权平均值。

 

找到最佳拆分的方法,即尝试每个变量和该变量的每个可能值,并查看哪个变量和哪个值为我们提供了最佳得分的划分。

 

这是创建决策树回归器的全部内容,并且当满足一些停止条件(由超参数定义)时将停止:

 

达到要求的限制时(例如max_depth)。

 

当你的叶子节点中只有一项(可能没有进一步划分,训练的MSE将为零,但是对其他数据集可能会过度拟合 – 不是一个有用的模型)。

 

是否有划分成3组的情况?

 

没有必要在一个级别上进行多次划分,因为您可以再进一步拆分它们。

 

它是如何进行预测的?

 

给定一个数据点,您可以在整个树中运行它,询问真/假,直到它到达叶节点为止。最终预测是该叶节点中因变量的值的平均值。

 

因为我们尝试了每个变量和每个变量可能的值来决策一个拆分。训练的计算成本会很高吗?

 

在这里,我们要记住,当今计算机的CPU性能是以千兆赫兹来衡量的,即每秒数十亿个时钟周期,它有多个核心,每个核心都有一个称为单指令、多数据(SIMD)的东西,它可以一次对每个核心进行8次计算。此外,如果您使用的是GPU,那幺这个过程会更快,因为它的性能是以teraflops来衡量的,所以每秒要进行数万亿次浮点运算。所以,这就是设计算法的地方,仅仅是人类很难意识到,考虑到当今计算机的速度有多快,算法应该多幺愚蠢。总而言之,有相当多的操作,但是每秒数万亿次的速度几乎注意不到。

 

每个节点的MSE计算哪个底层模型?

 

基础模型只是数据点的平均值。对于初始根节点,我们只是预测了所有训练数据点的因变量平均值。另一个可能的选择是不用平均数来使用中位数,或者我们甚至可以运行一个线性回归模型。我们可以做很多事情,但在实践中,平均值非常有效。它们确实存在在随机森林模型中,其中叶节点是独立的线性回归,但应用并不广泛。

 

给定相同的数据和超参数,深度为n的DT将包含深度为n-1的DT?

 

因此,如果我们创建一个深度为3的树和另一个我们摆脱最大深度的树,那幺没有最大深度约束的树将包含深度为3的树。这假设数据和超参数将是相同的并且没有添加随机性(更深的树将包含不太深的树)。

 

什幺时候不使用?

 

如前所述,如果提供给划分预测的数据与训练数据无关,决策树将无法做出准确的预测。让我们用一个例子来证明这个论点:

 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
x = np.linspace(0,1)
y = x + np.random.uniform(-0.2,0.2,x.shape)
plt.scatter(x,y)

 

 

我们现在要构建一个决策树模型,这实际上是一个时间序列问题。所以我打算将左侧部分作为训练集。并将右侧部分作为我们的验证集。

 

# train, validation set split
x_trn, x_val = x[:40,None], x[40:,None]
y_trn, y_val = y[:40,None], y[40:,None]
# fit a model
m = DecisionTreeRegressor(max_depth=6).fit(x_trn, y_trn)

 

请注意,决策树回归器期望二维数组,而不是二维数组中的一维数组。

 

 

我们现在绘制结果:

 

plt.scatter(x_val,m.predict(x_val),color='blue',label='Prediction') 
plt.scatter(x_val,y_val,color='red',label='Actual') 
plt.scatter(x_trn,m.predict(x_trn),color='blue') 
plt.scatter(x_trn,y_trn,color='red') 
plt.legend(loc='upper left')

 

 

如果您不知道决策树如何工作,那幺这将使模型无用。换句话说,决策树和基于树的模型通常无法推断出他们以前从未见过的任何类型的数据,特别是未来的时间段,因为它只是平均它已经看到的数据。

 

简而言之,决策树和基于树的模型一般只做一个聪明的最邻近法。

 

在这种问题中,任何基于树的算法都没有用,首选模型是神经网络或线性回归模型。原因是当你想要使用一个模型,而它有一个函数或者形状,它可以很好地进行外推。

 

 

决策树的一个主要缺点是它们容易过度拟合。这就是为什幺很少使用他们,而是使用其他基于树的模型,如随机森林和XGBoost。

 

总之,决策树和通用基于树的模型是一种监督学习算法(具有预定义的目标变量),主要用于分类问题。如上所述,当且仅当目标变量位于训练数据集中值的范围内时,它们才用于回归问题。

 

决策树的优缺点

 

 

优势

 

它可用于分类和回归问题有时间做的好一点。

 

易于理解,解释,可视化。

 

在数据探索中很有用:决策树是识别最重要变量和两个或多个变量之间关系的最快方法之一。借助决策树,我们可以创建新的变量/特征,这些变量/特征具有更好的预测目标变量的能力。

 

需要更少的数据准备:它不受异常值和缺失值的影响。

 

数据类型不是约束:它可以处理数值和分类变量。

 

非参数方法:决策树被认为是非参数方法。这意味着决策树没有关于空间分布和分类器结构的假设。

 

可以捕获非线性关系。

 

优势

 

过拟合:过拟合是决策树模型最实际的难点之一。通过设置模型参数约束和剪枝(下面详细讨论)可以解决这个问题。

 

不适合连续变量:在处理连续数值变量时,决策树在对不同类别的变量进行分类时会丢失信息。

 

无法推断。

 

决策树可能不稳定:数据的微小变化可能导致生成完全不同的树。这称为方差,需要通过bagging 和 boosting等方法降低。

 

无法保证返回全局最优决策树。这可以通过训练多个树来弥补,其中特征和样本随替换而随机取样。

 

避免过度拟合的技巧

 

通常,您可能会发现您的模型与数据过度匹配,这通常会在引入新数据时损害模型的性能。如果决策树没有限制集,它会在训练集上给你一个零MSE,因为在更糟的情况下,它最终会为每次观察生成一个叶子。因此,在训练决策树时,防止过度拟合非常重要,可以通过以下方式进行:

 

设置树大小的约束(微调超参数)

 

树剪枝

 

使用随机森林

 

让我们简单地讨论这些方面。

 

设置树的约束

 

这可以通过微调树的一些超参数来完成。首先,让我们看一下决策树的一般结构:

 

 

通过了解树建模中使用的参数的作用,可以帮助您在R&Python中更好地微调决策树。

 

节点拆分的最小样本

 

定义要考虑拆分的节点中所需的最小样本数(或观测值)。

 

用于控制过度拟合。较高的值会阻止模型学习与树选择的特定样本高度特别的关系。

 

太高的值会导致欠拟合,因此应该小心微调。

 

终端节点的最小样本(叶子)

 

定义终端节点或叶子中所需的最小样本(或观察值)。

 

用于控制过度拟合,类似于节点拆分的最小样本。

 

太高的值会导致欠拟合,因此应该小心微调。

 

树的最大深度(垂直深度)

 

用于控制过度拟合,因为更高的深度将使模型学习特定样本的关系。

 

太高的值会导致过度拟合,因此应小心微调。

 

拆分需要考虑的最大特征

 

搜索最佳拆分时要考虑的特征数量。这些将是随机选择的。

 

根据经验法则,特征总数的平方根非常有效,但我们应该检查特征总数的30-40%。

 

较高的值可能导致过度拟合,但取决于具体情况。

 

如前所述,设置约束的技术是一种贪婪方法。换句话说,它将立即检查最佳划分并向前移动,直到达到指定的停止条件之一。

 

决策树算法中出现的问题之一是最终树的最佳大小。太大的树存在过度拟合训练数据的风险,并且很难推广到新样本。小树可能无法捕获有关样本空间的重要结构信息。但是,很难判断树算法何时应该停止,因为无法判断添加单个额外节点是否会显着减少错误。这个问题被称为地平线效应。一种常见的策略是扩展树,直到每个节点包含少量实例,然后使用剪枝来删除不提供其他信息的节点。

 

剪枝应该减小学习树的大小,而不降低交叉验证集测量的预测精度。在用于优化性能的测量中,有许多不同的剪枝技术。

 

最简单的剪枝形式之一是减少错误剪枝。从叶子开始,每个节点都用其平均值替换。如果MSE不受影响,则保留更改。虽然有点天真,但减少错误剪枝具有简单和迅速的优点。

 

使用随机森林

 

似乎没有多少人真正花时间去剪枝决策树或进行微调,而是选择使用随机森林回归器(决策树集合),它比单个优化树更不容易过度拟合,性能更好。

 

决策树与随机森林

 

 

在随机森林上使用决策树的常见论点是,决策树更容易解释,您只需查看决策树逻辑即可。然而,在一个随机森林中,您不需要研究500个不同树的决策树逻辑。

 

同时,随机森林实际上是决策树的集合,这使得算法对于实时预测来说缓慢且无效。一般来说,RF可以快速训练,但是一旦训练开始就会很慢地创建预测。这是因为它必须对每棵树进行预测,然后进行平均以创建最终预测。(解决方法可以是同时使用不同树的集群)

 

更准确的预测需要更多的树,这会导致模型变慢。在大多数实际应用中,随机森林算法速度足够快,但在某些情况下,运行时性能是很重要的,所以会首选其他方法。

 

最后,决策树确实存在过度拟合问题,而随机森林可以防止过度拟合,从而在大多数情况下得到更好的预测。这是随机森林回归模型事实的一个显着优势,使其对许多数据科学家更具吸引力。

 

Sklearn决策树的超参数

 

 

min_samples_leaf  :int,float,optional(default = 1)

 

它是我们上面讨论的终端节点的最小样本数。

 

如果是int,则将min_samples_leaf视为最小数字。

 

如果是float,则min_samples_leaf是一个百分比,ceil(min_samples_leaf * n_samples)是每个节点的最小样本数。

 

min_samples_split:int,float,optional(default = 2)

 

它是我们上面讨论的节点拆分的最小样本。

 

如果是int,则将min_samples_split视为最小数字。

 

如果是float,则min_samples_split是一个百分比,ceil(min_samples_split * n_samples)是每个拆分的最小样本数。

 

max_features:int,float,string或None,optional(default =“auto”)

 

寻找最佳拆分时要考虑的特征数量:

 

如果是int,则在每次拆分时考虑max_features特征。 – 如果是浮点数,则max_features是百分比,并且在每次拆分时都会考虑int(max_features * n_features)要素。

 

如果是“auto”,则max_features = sqrt(n_features)。

 

如果是“sqrt”,则max_features = sqrt(n_features)(与“auto”相同)。

 

如果是“log2”,则max_features = log2(n_features)。

 

如果为None,则max_features = n_features。

 

max_depth :整数或无,可选(默认=无)

 

树的最大深度。如果为None,则扩展节点直到所有叶子都是纯的或直到所有叶子包含少于min_samples_split样本。

 

基于树的模型 VS 线性模型

 

实际上,您可以使用任何算法。这取决于您要解决的问题类型。让我们看一些关键因素,它们将帮助您决定使用哪种算法:

 

如果依赖变量和自变量之间的关系用线性模型很好地逼近,线性回归将优于基于树的模型。

 

如果因变量和自变量之间存在高度的非线性和复杂关系,树模型将优于经典的回归方法。

 

如果你需要建立一个易于向人们解释的模型,决策树模型总是比线性模型做得更好。决策树模型比线性回归更容易解释!

 

让我们用一个例子证明我们在第1点和第2点的论证:

 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
from sklearn.linear_model import LinearRegression
plt.figure(figsize=(20,10))
x = np.linspace(0,2,10000)
y = 1+ 3*x
plt.scatter(x,y)

 

 

我们现在要构建决策树和线性模型。我们期望线性模型完美拟合,因为目标变量与特征x线性相关。因此,我将对数据进行无序处理,将70%视为训练集,将30%视为验证。

 

idxs_train = sorted(np.random.permutation(len(x))[:int(0.7*len(x))])
idx_test = [i for i in range(0,len(x)) if i not in idxs_train]
# train, validation set split
x_trn, x_val = x[idxs_train,None], x[idx_test,None]
y_trn, y_val = y[idxs_train,None], y[idx_test,None]

# fit a model
dt = DecisionTreeRegressor(max_depth=3).fit(x_trn, y_trn)
l = LinearRegression().fit(x_trn, y_trn)

 

请注意,两个模型都期望二维数组。我们现在绘制结果:

 

plt.figure(figsize=(20,10))
plt.scatter(x,dt.predict(x[:,None]),color='blue',label='Prediction DT')
plt.scatter(x,l.predict(x[:,None]),color='green',label='Prediction Linear')
plt.scatter(x,y,color='red',label='Actual')
plt.legend(loc='upper left')

 

 

在某种程度上,决策树试图适应 staircase。显然,在这种情况下,线性模型运行得很好,但在目标变量与输入特征不线性相关的其他情况下,DT将是更好的选择,因为它能够捕获非线性。另请参阅以下SciKit学习文档中的另一个示例:

 

 

可视化决策树模型

 

可视化决策树非常简单。让我们绘制上面训练过的决策树。

 

首先,我们需要导入一些额外的库:

 

from sklearn.tree import export_graphviz
import IPython, graphviz, re, math

 

然后我们可以简单地绘制决策树,如下所示:

 

def draw_tree(t, col_names, size=9, ratio=0.5, precision=3):
""" Draws a representation of a random forest in IPython.
    Parameters:
    -----------
    t: The tree you wish to draw
    df: The data used to train the tree. This is used to get the names of the features.
    """
    s=export_graphviz(t, out_file=None, feature_names=col_names, filled=True,
                      special_characters=True, rotate=True, precision=precision)
    IPython.display.display(graphviz.Source(re.sub('Tree {',
f'Tree {{ size={size}; ratio={ratio}',s)))
col_names =['X']
draw_tree(dt, col_names, precision=3)

 

 

如您所见,我们正在获取数据的子集,并决定进一步划分子集的最佳方式。我们的初始子集是整个数据集,我们根据规则对其进行拆分X<=1.001。然后,对于每个子集,我们执行额外的拆分,直到我们能够正确地预测目标变量,同时遵守约束max_depth=3。

 

决策树是最广泛使用的机器学习模型之一,因为它们可以很好地处理噪声或丢失的数据,并且可以很容易地进行整合以形成更强大的预测器。此外,您可以直接看到模型的学习逻辑,这意味着它是一个非常受欢迎的模型,适用于模型可解释性很重要的领域。

 

感谢阅读,我期待着听到你的问题,敬请关注并快乐机器学习。

 

https://scikit-learn.org/stable/modules/tree.html

 

https://en.wikipedia.org/wiki/Decision_tree_pruning

 

https://stackoverflow.com/questions/49428469/pruning-decision-trees

 

作者:Georgios Drakos

Be First to Comment

发表评论

邮箱地址不会被公开。 必填项已用*标注