Python手写决策树并应对过度拟合问题

简介: Python手写决策树并应对过度拟合问题

640.png

介绍

决策树是一种用于监督学习的算法。它使用树结构,其中包含两种类型的节点:决策节点和叶节点。决策节点通过在要素上询问布尔值将数据分为两个分支。叶节点代表一个类。训练过程是关于在具有特定特征的特定特征中找到“最佳”分割。预测过程是通过沿着路径的每个决策节点回答问题来从根到达叶节点。

基尼不纯度和熵

术语“最佳”拆分是指拆分之后,两个分支比任何其他可能的拆分更“有序”。我们如何定义更多有序的?这取决于我们选择哪种指标。通常,度量有两种类型:基尼不纯度和熵。这些指标越小,数据集就越“有序”。

640.png

这两个指标之间的差异非常微妙。但 在大多数应用中,两个指标的行为类似。以下是用于计算每个指标的代码。

defgini_impurity(y):
#calculategini_impuritygivenlabels/classesofeachexamplem=y.shape[0]
cnts=dict(zip(*np.unique(y, return_counts=True)))
impurity=1-sum((cnt/m)**2forcntincnts.values())
returnimpuritydefentropy(y):
#calculateentropygivenlabels/classesofeachexamplem=y.shape[0]
cnts=dict(zip(*np.unique(y, return_counts=True)))
disorder=-sum((cnt/m)*log(cnt/m) forcntincnts.values())
returndisorder

构建树

训练过程实质上是在树上建树。关键步骤是确定“最佳”分配。过程如下:我们尝试按每个功能中的每个唯一值分割数据,然后选择混乱程度最小的最佳数据。现在我们可以将此过程转换为python代码。

defget_split(X, y):
#loopthroughfeaturesandvaluestofindbestcombinationwiththemostinformationgainbest_gain, best_index, best_value=0, None, Nonecur_gini=gini_impurity(y)
n_features=X.shape[1]  
forindexinrange(n_features):  
values=np.unique(X[:, index], return_counts=False)  
forvalueinvalues:  
left, right=test_split(index, value, X, y)
ifleft['y'].shape[0] ==0orright['y'].shape[0] ==0:
continuegain=info_gain(left['y'], right['y'], cur_gini)
ifgain>best_gain:
best_gain, best_index, best_value=gain, index, valuebest_split= {'gain': best_gain, 'index': best_index, 'value': best_value}
returnbest_splitdeftest_split(index, value, X, y):
#splitagroupofexamplesbasedongivenindex (feature) andvaluemask=X[:, index] <valueleft= {'X': X[mask, :], 'y': y[mask]}
right= {'X': X[~mask, :], 'y': y[~mask]}
returnleft, rightdefinfo_gain(l_y, r_y, cur_gini):
#calculatetheinformationgainforacertainsplitm, n=l_y.shape[0], r_y.shape[0]
p=m/ (m+n)
returncur_gini-p*gini_impurity(l_y) - (1-p) *gini_impurity(r_y)

在构建树之前,我们先定义决策节点和叶节点。决策节点指定将在其上拆分的特征和值。它还指向左,右子项。叶节点包括类似于Counter对象的字典,该字典显示每个类有多少训练示例。这对于计算训练的准确性很有用。另外,它导致到达该叶子的每个示例的结果预测。

classDecision_Node:
#defineadecisionnodedef__init__(self, index, value, left, right):
self.index, self.value=index, valueself.left, self.right=left, rightclassLeaf:
#definealeafnodedef__init__(self, y):
self.counts=dict(zip(*np.unique(y, return_counts=True)))
self.prediction=max(self.counts.keys(), key=lambdax: self.counts[x])

鉴于其结构,通过递归构造树是最方便的。递归的出口是叶节点。当我们无法通过拆分提高数据纯度时,就会发生这种情况。如果我们可以找到“最佳”拆分,则这将成为决策节点。然后,我们对其左,右子级递归执行相同的操作。

defdecision_tree(X, y):
#trainthedecisiontreemodelwithadatasetcorrect_prediction=0defbuild_tree(X, y):
#recursivelybuildthetreesplit=get_split(X, y)
ifsplit['gain'] ==0:
nonlocalcorrect_predictionleaf=Leaf(y)
correct_prediction+=leaf.counts[leaf.prediction]
returnleafleft, right=test_split(split['index'], split['value'], X, y)
left_node=build_tree(left['X'], left['y'])
right_node=build_tree(right['X'], right['y'])
returnDecision_Node(split['index'], split['value'], left_node, right_node)
root=build_tree(X, y)
returncorrect_prediction/y.shape[0], root

预测

现在我们可以遍历树直到叶节点来预测一个示例。

defpredict(x, node):
ifisinstance(node, Leaf):
returnnode.predictionifx[node.index] <node.value:
returnpredict(x, node.left)
else:
returnpredict(x, node.right)

事实证明,训练精度为100%,决策边界看起来很奇怪!显然,该模型过度拟合了训练数据。好吧,如果考虑到这一点,如果我们继续拆分直到数据集变得更纯净,决策树将过度适合数据。换句话说,如果我们不停止分裂,该模型将正确分类每个示例!训练准确性为100%(除非具有完全相同功能的不同类别的示例),这丝毫不令人惊讶。

640.png

如何应对过度拟合?

从上一节中,我们知道决策树过拟合的幕后原因。为了防止过度拟合,我们需要在某个时候停止拆分树。因此,我们需要引入两个用于训练的超参数。它们是:树的最大深度和叶子的最小尺寸。让我们重写树的构建部分。

defdecision_tree(X, y, max_dep=5, min_size=10):
#trainthedecisiontreemodelwithadatasetcorrect_prediction=0defbuild_tree(X, y, dep, max_dep=max_dep, min_size=min_size):
#recursivelybuildthetreesplit=get_split(X, y)
ifsplit['gain'] ==0ordep>=max_depory.shape[0] <=min_size:
nonlocalcorrect_predictionleaf=Leaf(y)
correct_prediction+=leaf.counts[leaf.prediction]
returnleafleft, right=test_split(split['index'], split['value'], X, y)
left_node=build_tree(left['X'], left['y'], dep+1)
right_node=build_tree(right['X'], right['y'], dep+1)
returnDecision_Node(split['index'], split['value'], left_node, right_node)
root=build_tree(X, y, 0)
returncorrect_prediction/y.shape[0], root

现在我们可以重新训练数据并绘制决策边界。

640.png

树的可视化

接下来,我们将通过打印出决策树的节点来可视化决策树。节点的压痕与其深度成正比。

defprint_tree(node, indent="|---"):
#printthetreeifisinstance(node, Leaf):
print(indent+'Class:', node.prediction)
returnprint(indent+'feature_'+str(node.index) +' <= '+str(round(node.value, 2)))
print_tree(node.left, '|   '+indent)
print(indent+'feature_'+str(node.index) +' > '+str(round(node.value, 2)))
print_tree(node.right, '|   '+indent)

结果如下:

|---feature_1<=1.87||---feature_1<=-0.74|||---feature_1<=-1.79||||---feature_1<=-2.1|||||---Class: 2||||---feature_1>-2.1|||||---Class: 2|||---feature_1>-1.79||||---feature_0<=1.62|||||---feature_0<=-1.31||||||---Class: 2|||||---feature_0>-1.31||||||---feature_1<=-1.49|||||||---Class: 1||||||---feature_1>-1.49|||||||---Class: 1||||---feature_0>1.62|||||---Class: 2||---feature_1>-0.74|||---feature_1<=0.76||||---feature_0<=0.89|||||---feature_0<=-0.86||||||---feature_0<=-2.24|||||||---Class: 2||||||---feature_0>-2.24|||||||---Class: 1|||||---feature_0>-0.86||||||---Class: 0||||---feature_0>0.89|||||---feature_0<=2.13||||||---Class: 1|||||---feature_0>2.13||||||---Class: 2|||---feature_1>0.76||||---feature_0<=-1.6|||||---Class: 2||||---feature_0>-1.6|||||---feature_0<=1.35||||||---feature_1<=1.66|||||||---Class: 1||||||---feature_1>1.66|||||||---Class: 1|||||---feature_0>1.35||||||---Class: 2|---feature_1>1.87||---Class: 2

总结

与其他回归模型不同,决策树不使用正则化来对抗过度拟合。相反,它使用树修剪。选择正确的超参数(树的深度和叶子的大小)还需要进行实验,例如 使用超参数矩阵进行交叉验证。

对于完整的工作流,包括数据生成和绘图决策边界,完整的代码在这里:https://github.com/JunWorks/ML-Algorithm-with-Python/blob/master/decision_tree/decision_tree.ipynb



目录
相关文章
|
1月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
34 4
|
1天前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【9月更文挑战第12天】决策树算法作为机器学习领域的一颗明珠,凭借其直观易懂和强大的解释能力,在分类与回归任务中表现出色。相比传统统计方法,决策树通过简单的分支逻辑实现了数据的精准分类。本文将借助Python和scikit-learn库,以鸢尾花数据集为例,展示如何使用决策树进行分类,并探讨其优势与局限。通过构建一系列条件判断,决策树不仅模拟了人类决策过程,还确保了结果的可追溯性和可解释性。无论您是新手还是专家,都能轻松上手,享受机器学习的乐趣。
13 9
|
4天前
|
机器学习/深度学习 算法 Python
从菜鸟到大师:一棵决策树如何引领你的Python机器学习之旅
【9月更文挑战第9天】在数据科学领域,机器学习如同璀璨明珠,吸引无数探索者。尤其对于新手而言,纷繁复杂的算法常让人感到迷茫。本文将以决策树为切入点,带您从Python机器学习的新手逐步成长为高手。决策树以其直观易懂的特点成为入门利器。通过构建决策树分类器并应用到鸢尾花数据集上,我们展示了其基本用法及效果。掌握决策树后,还需深入理解其工作原理,调整参数,并探索集成学习方法,最终将所学应用于实际问题解决中,不断提升技能。愿这棵智慧之树助您成为独当一面的大师。
14 3
|
6天前
|
机器学习/深度学习 算法 Python
决策树下的智慧果实:Python机器学习实战,轻松摘取数据洞察的果实
【9月更文挑战第7天】当我们身处数据海洋,如何提炼出有价值的洞察?决策树作为一种直观且强大的机器学习算法,宛如智慧之树,引领我们在繁复的数据中找到答案。通过Python的scikit-learn库,我们可以轻松实现决策树模型,对数据进行分类或回归分析。本教程将带领大家从零开始,通过实际案例掌握决策树的原理与应用,探索数据中的秘密。
15 1
|
16天前
|
Python
Python笔下那些神奇的树
Python笔下那些神奇的树
|
1月前
|
机器学习/深度学习 前端开发 数据挖掘
基于Python Django的房价数据分析平台,包括大屏和后台数据管理,有线性、向量机、梯度提升树、bp神经网络等模型
本文介绍了一个基于Python Django框架开发的房价数据分析平台,该平台集成了多种机器学习模型,包括线性回归、SVM、GBDT和BP神经网络,用于房价预测和市场分析,同时提供了前端大屏展示和后台数据管理功能。
|
1月前
|
数据采集 机器学习/深度学习 算法
【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】
【python】python客户信息审计风险决策树算法分类预测(源码+数据集+论文)【独一无二】
|
1月前
|
数据可视化 Python
【2023高教社杯】C题 蔬菜类商品的自动定价与补货决策 问题分析、数学模型及python代码实现
本文介绍了2023年高教社杯数学建模竞赛C题,涉及蔬菜类商品的自动定价与补货决策,包括问题分析、数学模型的构建以及Python代码实现,旨在优化商超的补货和定价策略以提高收益。
58 1
|
1月前
|
Python
【Leetcode刷题Python】538. 把二叉搜索树转换为累加树
LeetCode上538号问题"把二叉搜索树转换为累加树"的Python实现,使用反向中序遍历并记录节点值之和来更新每个节点的新值。
17 3
|
1月前
|
机器学习/深度学习 算法 数据挖掘
决策树算法大揭秘:Python让你秒懂分支逻辑,精准分类不再难
【8月更文挑战第2天】决策树算法以其直观性和解释性在机器学习领域中独具魅力,尤其擅长处理非线性关系。相较于复杂模型,决策树通过简单的分支逻辑实现数据分类,易于理解和应用。本示例通过Python的scikit-learn库演示了使用决策树对鸢尾花数据集进行分类的过程,并计算了预测准确性。虽然决策树优势明显,但也存在过拟合等问题。即便如此,无论是初学者还是专家都能借助决策树的力量提升数据分析能力。
25 4