Python机器学习系列之scikit-learn决策树原理简要概述
off999 2024-11-26 07:24 16 浏览 0 评论
1.概述
1.1决策树是如何工作的
决策树是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归的问题。决策树算法容易理解,适用于各种数据集,在解决各种问题时都有良好的表现,尤其是以树模型为核心的各种集成算法,在各个行业和领域都有广泛的应用。
我们来简单了解一下决策树是如何工作的,决策树算法的本质是一种图形结构,我们只需要问一系列问题就可以对数据进行分类。
通过上面的例子,我们很容易理解:决策树算法的本质就是树形结构,我们可以通过一些精心设计的问题,就可以对数据进行分类了。在这里,我们需要了解三个概念:
节点 | 说明 |
根节点 | 没有进边,有出边 |
中间节点 | 既有进边也有出边,但进边有且只有一条,出边也可以有很多条 |
叶节点 | 只有进边,没有出边,进边有且只有一条,每个页节点都是一个类别标签 |
父节点和字节点 | 在两个相连的节点中,更靠近根节点的是父节点,另一个则是子节点,两者是相对的 |
我们可以把决策树看作是一个if-then规则的集合,将决策树转换成if-then规则的过程是这样的:
- 由决策树的根节点到叶节点的每一条路径构建一条规则;
- 路径上中间节点的特征对应着规则的条件,也就是叶子节点的类标签对应着规则的结论;
决策树的路径或者其对应的if-then规则集合有一个重要的性质:互斥并且完备。也就是说,每一个实例都被有且仅有一条路径或者规则所覆盖。这里的覆盖是指实例的特征与路径上的特征一致,或者实例满足规则的条件。
决策树算法的核心是要解决两个问题:
- 如何从数据集中找出最佳节点和最佳分支?
- 如何让决策树停止生长,防止过度拟合?
几乎所有决策树有关的模型调整方法,都围绕这两个问题展开。这两个问题背后的原理十分复杂,我们会在讲解模型参数和属性的时候为大家简单解释涉及到的部分。
1.2决策树的构建准备工作
使用决策树做分类的每一步骤都很重要,首先我们要收集足够多的数据,如果数据收集不到位,将会导致没有足够的特征去构建错误率低的决策树。数据特征充足,但是不知道用哪些特征好,也会导致最终无法构建出分类效果好的决策树。从算法层面来看的话,决策树的构建就是我们的核心内容。
决策树如何构建呢?通常,这一过程可以概括为三个步骤:
- 特征选择;
- 决策树的生成;
- 决策树的剪枝;
特征选择就是决定用哪些特征来划分特征空间,其目的在于选取对训练数据具有分类能力的特征,这样可以提高决策树的学习效率。如果利用一个特征进行分类的结果与随机分类的结果没有很大的差别,则称这个特征是没有分类能力的,经验上扔掉这些特征对决策树学习的精度影响不会很大。
1.3sklearn中的决策树
- 模块sklearn.tree
sklearn中决策树的类都在“tree”这个模块之下,这个模块总共包含五个类:
tree.DecisionTreeClassifier | 分类树 |
tree.DecisionTreeRegressor | 回归树 |
tree.export_graphviz | 将生成的决策树导出为DOT格式,画图专用 |
tree.ExtraTreeClassifier | 高随机版本的分类树 |
tree.ExtraTreeRegressor | 高随机版本的回归树 |
- sklearn的基本建模流程
在这个流程下,分类树对应的代码是:
#导入需要的模块
from sklearn.tree import DecisionTreeClassifier
#实例化
clf = DecisionTreeClassifier()
#用训练集数据训练模型
clf.fit(x, y)
#导入测试集,从接口中调用需要的信息
result = clf.score(X_test,y_test)
#使用训练好的模型进行预测
clf.predict(test)
2.DecisionTreeClassifier模型
class sklearn.tree.DecisionTreeClassifier (criterion='gini', splitter='best', max_depth=None,
min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None,
random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None,
class_weight=None, presort=False)
2.1 重要参数
2.1.1 criterion
为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分支方法,对分类树来说,衡量这个”最佳“的指标叫做”不纯度“。通常来说,不纯度越低,决策树对训练集的拟合越好。现在使用的决策树算法在分枝方法上的核心大多是围绕在对某个不纯度相关指标的最优化上。
不纯度基于节点来计算,树中的每一个节点都会有一个不纯度,并且字节点的不纯度一定是低于父节点的不纯度;也就是说,同一棵决策树上,叶子节点上的不纯度一定是最低的。
Criterion这个参数正是用来决定不纯度的计算方法的,sklearn提供了两种选择:
- 输入”entropy“,使用信息熵;
- 输入”gini“,使用基尼系数;
比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长会更加“精细”,因此对于高维数据或者噪音很多的数据,信息熵很容易过拟合,基尼系数在这种情况下效果往往比较好。当模型拟合程度不足的时候,即当模型在训练集和测试集上都表现不太好的时候,使用信息熵。当然,这些不是绝对的。
参数 | criterion |
如何影响模型? | 确定不纯度的计算方法,帮助找出最佳节点和最佳分支,不纯度越低,决策树对训练集的拟合越好 |
可能的输入有哪些? | 不填默认基尼系数,填写gini使用基尼系数,填写entropy使用信息增益 |
怎样选取参数? | 通常就使用基尼系数 数据维度很大,噪音很多的时候使用基尼系数 维度低,数据比较清晰的时候,信息熵和基尼系数没区别 当决策树的拟合程度不够的时候,使用信息熵 |
到这里,决策树的基本流程其实可以简单概括如下:
直到没有更多的特征可用,或者整体的不纯度指标已经最优,决策树就会停止生长。
建立一棵树
1.导入需要的算法库和模块
from sklearn.datasets import load_digits
from sklearn.tree import DecisionTreeClassifier
2.探索数据
dataset = load_digits()
dataset
dataset.data.shape
dataset.target.shape
dataset.target_names
import pandas as pd
pd.concat([pd.DataFrame(dataset.data), pd.DataFrame(dataset.target)], axis=1)
3.分训练集和测试集
from sklearn.model_selection import train_test_split
xtrain, xtest, ytrain, ytest = train_test_split(data, dataset.target, test_size=0.3, shuffle=False)
xtrain.shape
ytest.shape
4.建立模型
clf = DecisionTreeClassifier()
clf = clf.fit(xtrain, ytrain)
score = clf.score(xtest, ytest)
score
5.画出一棵树
import graphviz
from sklearn.tree import export_graphviz
graph_data = export_graphviz(clf,
feature_names=list(dataset.feature_names),
class_names=f)
graph = graphviz.Source(graph_data)
graph
6.探索决策树
clf.feature_importances_
[*zip(dataset.feature_names, clf.feature_importances_)]
2.1.2 random_state & splitter
random_state用来设置分支中的随机模式的参数,默认None;在高维度时随机性会表现更明显,低纬度的数据,随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。
splitter也是用来控制决策树中的随机选项的,有两种输入值,输入”best“,决策树在分支时虽然随机,但是还是会优先选择更重要的特征进行分支(重要性可以通过属性feature_importances_查看),输入”random“,决策树在分支时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这也是防止过拟合的一种方式。当你预测到你的模型会过拟合,用这两个参数来帮助你降低树建成之后过拟合的可能性。当然,树一旦建成,我们依然是使用剪支参数来防止过拟合。
2.1.3 剪枝参数
在不加限制的情况下,一棵决策树会生长到衡量不纯度的指标最优,或者没有更多的特征可用为止。这样的决策树往往会过拟合,这就是说,它会在训练集上表现很好,但在测试集上却表现糟糕。我们收集的样本数据不可能和整体的状况完全一致,因此当一棵决策树对训练数据有了过于优秀的解释性,它找出的规则必然包含了训练样本中的噪声,并使它对未知数据的拟合程度不足。
为了让决策树有更好的泛化性,我们要对决策树进行剪枝。剪枝策略对决策树的影响巨大,正确的剪枝策略是优化决策树算法的核心。sklearn为我们提供了不同的剪枝策略:
- max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉
这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。实际使用时,建议从=3开始尝试,看看拟合的效果再决定是否增加设定深度。
- min_samples_leaf & min_samples_split
min_samples_leaf限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生
一般搭配max_depth使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。一般来说,建议从=5开始使用。如果叶节点中含有的样本量变化很大,建议输入浮点数作为样本量的百分比来使用。同时,这个参数可以保证每个叶子的最小尺寸,可以在回归问题中避免低方差,过拟合的叶子节点出现。对于类别不多的分类问题,=1通常就是最佳选择。
min_samples_split限定,一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生。
- max_features & min_impurity_decrease
一般max_depth使用,用作树的”精修“
max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。和max_depth异曲同工,max_features是用来限制高维度数据的过拟合的剪枝参数,但其方法比较暴力,是直接限制可以使用的特征数量而强行使决策树停下的参数,在不知道决策树中的各个特征的重要性的情况下,强行设定这个参数可能会导致模型学习不足。如果希望通过降维的方式防止过拟合,建议使用PCA,ICA或者特征选择模块中的降维算法。
- 确认最优的剪枝参数
那具体怎么来确定每个参数填写什么值呢?这时候,我们就要使用确定超参数的曲线来进行判断了,继续使用我们已经训练好的决策树模型clf。超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线。在我们建好的决策树里,我们的模型度量指标就是score。
无论如何,剪枝参数的默认值会让树无尽地生长,这些树在某些数据集上可能非常巨大,对内存的消耗也非常巨大。所以如果你手中的数据集非常巨大,你已经预测到无论如何你都是要剪枝的,那提前设定这些参数来控制树的复杂性和大小会比较好。
2.1.4 目标权重参数
- class_weight & min_weight_fraction_leaf
完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。比如说,在银行要判断“一个办了信用卡的人是否会违约”,就是是vs否(1%:99%)的比例。这种分类状况下,即便模型什么也不做,全把结果预测成“否”,正确率也能有99%。因此我们要使用class_weight参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认None,此模式表示自动给与数据集中的所有标签相同的权重。
有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_weight_fraction_leaf这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如min_weight_fraction_leaf)将比不知道样本权重的标准(比如min_samples_leaf)更少偏向主导类。如果样本是加权的,则使用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。
2.2 重要属性和接口
属性是在训练模型之后,能够调用查看的模型的各种性质。对决策树来说,最重要的是feature_importances_,能够查看各个特征对模型的重要性。
sklearn中许多算法的接口都是相似的,比如说我们之前已经用到的fit和score,几乎对每个算法都可以使用。除了这两个接口之外,决策树最常用的接口还有apply和predict。apply中输入测试集返回每个测试样本所在的叶子节点的索引,predict输入测试集返回每个测试样本的标签。
所有接口中要求输入x_train和x_test的部分,输入的特征矩阵必须至少是一个二维矩阵。sklearn不接受任何一维矩阵作为特征矩阵被输入。如果数据的确只有一个特征,那必须用reshape(-1,1)来给矩阵增维;如果数据只有一个特征和一个样本,使用reshape(1,-1)来给你的数据增维。
3.决策树总结
3.1决策树的优点
- 决策树可以可视化,容易理解和解释,因为决策树可以画出来被看见;
- 数据准备工作很少,其他很多算法通常都需要数据规范化,需要创建虚拟变量并删除空值等;但请注意,sklearn中的决策树模块不支持对缺失值的处理。
- 使用树的成本(比如说,在预测数据的时候)是用于训练树的数据点的数量的对数,相比于其他算法,这是一个很低的成本。
- 能够同时处理数值和分类数据,既可以做回归又可以做分类,其他技术通常专门用于分析仅具有一种变量类型的数据集;
- 效率高,决策树只需要一次构建,反复使用,每一次预测的最大计算次数不超过决策树的深度;
- 能够处理多输出问题,即含有多个标签的问题,注意与一个标签中含有多种标签分类的问题区别开;
- 是一个白盒模型,结果很容易能够被解释;如果在模型中可以观察到给定的情况,则可以通过布尔逻辑轻松解释条件;相反,在黑盒模型中,结果可能更难以解释。
- 可以使用统计测试验证模型,这让我们可以考虑模型的可靠性。
- 即使其假设在某种程度上违反了生成数据的真实模型,也能够表现良好。
3.2决策树的缺点
- 决策树学习者可能创建过于复杂的树,这些树不能很好地推广数据。这称为过度拟合。修剪,设置叶节点所需的最小样本数或设置树的最大深度等机制是避免此问题所必需的,而这些参数的整合和调整对初学者来说会比较晦涩
- 决策树可能不稳定,数据中微小的变化可能导致生成完全不同的树,这个问题需要通过集成算法来解决。
- 决策树的学习是基于贪婪算法,它靠优化局部最优(每个节点的最优)来试图达到整体的最优,但这种做法不能保证返回全局最优决策树。这个问题也可以由集成算法来解决,在随机森林中,特征和样本会在分枝过程中被随机采样。
- 有些概念很难学习,因为决策树不容易表达它们,例如XOR,奇偶校验或多路复用器问题。
- 如果标签中的某些类占主导地位,决策树学习者会创建偏向主导类的树。因此,建议在拟合决策树之前平衡数据集。
3.3决策树复杂性
一般来说,构建平衡二叉树的运行时间成本为和查询时间。尽管树构建算法尝试生成平衡树,但它们并不总是平衡的。假设子树保持近似平衡,每个节点的成本包括搜索找到提供最大熵减少的特征。这有一个成本在每个节点,导致整个树的总成本(通过对每个节点的成本求和)。
3.4实际使用小贴士
- 决策树倾向于过度拟合具有大量特征的数据,获得正确的样本与特征数量的比率很重要,因为在高维空间中样本很少的树很可能会过度拟合。
- 考虑事先执行降维(PCA,ICA或者Feature selection),以使你的树有更好的机会找到具有判别力的特征。
- 了解决策树结构将有助于深入了解决策树如何进行预测,这对于理解数据中的重要特征很重要。
- 使用该export 函数在训练时可视化您的树。使用max_depth=3作为初始树深度得到的树是如何装修你的数据的感觉,再增加深度。
- 树增长到每一个额外的级别,填充树所需的样本数量就会加倍。使用max_depth控制树,以防止过度拟合的大小。
- 通过控制将考虑哪些拆分,使用min_samples_split或min_samples_leaf确保多个样本通知树中的每个决策。非常小的数字通常意味着树会过拟合,而较大的数字会阻止树学习数据。尝试 min_samples_leaf=5作为初始值。如果样本大小变化很大,可以在这两个参数中使用浮点数作为百分比。虽然min_samples_split可以创建任意小的叶子, min_samples_leaf保证每个叶子都有一个最小的尺寸,避免回归问题中低方差、过拟合的叶子节点。对于类较少的分类,min_samples_leaf=1往往是最好的选择。
- 请注意,如果提供,则min_samples_split直接考虑样本并且独立于 sample_weight,(例如,具有 m 个加权样本的节点仍然被视为具有恰好 m 个样本)。考虑min_weight_fraction_leaf或 min_impurity_decrease是否需要在拆分时考虑样本权重。
- 在训练之前平衡您的数据集,以防止树偏向于占主导地位的类。类平衡可以通过从每个类中采样相等数量的样本来完成,或者最好通过将每个类的样本权重 ( sample_weight)的总和归一化为相同的值来完成。还要注意,基于权重的预剪枝标准(例如 )min_weight_fraction_leaf将比不知道样本权重的标准(例如 )更偏向于主导类min_samples_leaf。
- 如果对样本进行加权,则使用基于权重的预剪枝标准(例如 )将更容易优化树结构 min_weight_fraction_leaf,这确保叶节点至少包含样本权重总和的一小部分。
- 所有决策树np.float32内部都使用数组。如果训练数据不是这种格式,将制作数据集的副本。
- 如果输入矩阵X非常稀疏,建议csc_matrix在调用fit之前先转换为sparse ,csr_matrix在调用predict之前先转换为sparse 。当特征在大多数样本中为零时,稀疏矩阵输入的训练时间比密集矩阵快几个数量级。
3.5决策树算法:ID3,C4.5,C5.0和CART
各种决策树的算法是什么,它们之间有何不同?scikit-learn中实现了哪一个?
- ID3 (Iterative Dichotomiser 3) 是由 Ross Quinlan 于 1986 年开发的。该算法创建了一个多路树,为每个节点(即以贪婪的方式)找到将为分类目标产生最大信息增益的分类特征。树生长到它们的最大大小,然后通常应用修剪步骤来提高树泛化到看不见的数据的能力。
- C4.5 是 ID3 的后继者,并通过动态定义将连续属性值划分为一组离散区间的离散属性(基于数值变量)取消了特征必须是分类的限制。C4.5 将训练好的树(即 ID3 算法的输出)转换为 if-then 规则集。然后评估每个规则的这些准确性,以确定它们的应用顺序。如果没有规则的准确性提高,则通过删除规则的先决条件来完成修剪。
- C5.0 是 Quinlan 在专有许可下发布的最新版本。与 C4.5 相比,它使用更少的内存并构建更小的规则集,同时更准确。
- CART(分类和回归树)与 C4.5 非常相似,但不同之处在于它支持数值目标变量(回归)并且不计算规则集。CART 使用在每个节点产生最大信息增益的特征和阈值构建二叉树。
scikit-learn使用CART算法的优化版本;但是,scikit-learn的实现目前不支持分类变量。
不积跬步,无以至千里;
不积小流,无以成江海;
参考资料:
https://scikit-learn.org/stable/modules/tree.html
相关推荐
- 面试官:来,讲一下枚举类型在开发时中实际应用场景!
-
一.基本介绍枚举是JDK1.5新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错...
- 一日一技:11个基本Python技巧和窍门
-
1.两个数字的交换.x,y=10,20print(x,y)x,y=y,xprint(x,y)输出:102020102.Python字符串取反a="Ge...
- Python Enum 技巧,让代码更简洁、更安全、更易维护
-
如果你是一名Python开发人员,你很可能使用过enum.Enum来创建可读性和可维护性代码。今天发现一个强大的技巧,可以让Enum的境界更进一层,这个技巧不仅能提高可读性,还能以最小的代价增...
- Python元组编程指导教程(python元组的概念)
-
1.元组基础概念1.1什么是元组元组(Tuple)是Python中一种不可变的序列类型,用于存储多个有序的元素。元组与列表(list)类似,但元组一旦创建就不能修改(不可变),这使得元组在某些场景...
- 你可能不知道的实用 Python 功能(python有哪些用)
-
1.超越文件处理的内容管理器大多数开发人员都熟悉使用with语句进行文件操作:withopen('file.txt','r')asfile:co...
- Python 2至3.13新特性总结(python 3.10新特性)
-
以下是Python2到Python3.13的主要新特性总结,按版本分类整理:Python2到Python3的重大变化Python3是一个不向后兼容的版本,主要改进包括:pri...
- Python中for循环访问索引值的方法
-
技术背景在Python编程中,我们经常需要在循环中访问元素的索引值。例如,在处理列表、元组等可迭代对象时,除了要获取元素本身,还需要知道元素的位置。Python提供了多种方式来实现这一需求,下面将详细...
- Python enumerate核心应用解析:索引遍历的高效实践方案
-
喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。根据GitHub代码分析统计,使用enumerate替代range(len())写法可减少38%的索引错误概率。本文通过12个生产...
- Python入门到脱坑经典案例—列表去重
-
列表去重是Python编程中常见的操作,下面我将介绍多种实现列表去重的方法,从基础到进阶,帮助初学者全面掌握这一技能。方法一:使用集合(set)去重(最简单)pythondefremove_dupl...
- Python枚举类工程实践:常量管理的标准化解决方案
-
本文通过7个生产案例,系统解析枚举类在工程实践中的应用,覆盖状态管理、配置选项、错误代码等场景,适用于Web服务开发、自动化测试及系统集成领域。一、基础概念与语法演进1.1传统常量与枚举类对比#传...
- 让Python枚举更强大!教你玩转Enum扩展
-
为什么你需要关注Enum?在日常开发中,你是否经常遇到这样的代码?ifstatus==1:print("开始处理")elifstatus==2:pri...
- Python枚举(Enum)技巧,你值得了解
-
枚举(Enum)提供了更清晰、结构化的方式来定义常量。通过为枚举添加行为、自动分配值和存储额外数据,可以提升代码的可读性、可维护性,并与数据库结合使用时,使用字符串代替数字能简化调试和查询。Pytho...
- 78行Python代码帮你复现微信撤回消息!
-
来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。[导读]Python曾经对我说:"时日不多,赶紧用Python"。于是看...
- 登录人人都是产品经理即可获得以下权益
-
文章介绍如何利用Cursor自动开发Playwright网页自动化脚本,实现从选题、写文、生图的全流程自动化,并将其打包成API供工作流调用,提高工作效率。虽然我前面文章介绍了很多AI工作流,但它们...
- Python常用小知识-第二弹(python常用方法总结)
-
一、Python中使用JsonPath提取字典中的值JsonPath是解析Json字符串用的,如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的,使用jsonpat...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python自定义函数 (53)
- python进度条 (67)
- python吧 (67)
- python字典遍历 (54)
- python的for循环 (65)
- python格式化字符串 (61)
- python串口编程 (60)
- python读取文件夹下所有文件 (59)
- java调用python脚本 (56)
- python操作mysql数据库 (66)
- python字典增加键值对 (53)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python人脸识别 (54)
- python多态 (60)
- python命令行参数 (53)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)