当前位置: 首页 > news >正文

决策树模型实战指南:避免过拟合、欠拟合与无关特征

【精选优质专栏推荐】

  • 《AI 技术前沿》—— 紧跟 AI 最新趋势与应用
  • 《网络安全新手快速入门(附漏洞挖掘案例)》—— 零基础安全入门必看
  • 《BurpSuite 入门教程(附实战图文)》—— 渗透测试必备工具详解
  • 《网安渗透工具使用教程(全)》—— 一站式工具手册
  • 《CTF 新手入门实战教程》—— 从题目讲解到实战技巧
  • 《前后端项目开发(新手必知必会)》—— 实战驱动快速上手


每个专栏均配有案例与图文讲解,循序渐进,适合新手与进阶学习者,欢迎订阅。

文章目录

    • 前言
    • 1. 过拟合:记住数据而非从数据中学习
    • 2. 欠拟合:树太简单而无法良好工作
    • 3. 误导性的训练特征:引起干扰
    • 总结

前言

在本文中,你将了解决策树在实践中有时会失败的原因,以及如何用简单有效的技术纠正常见问题。

我们将涵盖的主题包括:

  • 如何发现并减少决策树的过拟合。
  • 如何通过调整模型容量识别并修复欠拟合。
  • 噪声或冗余特征如何误导决策树,以及特征选择如何提供帮助。

基于决策树的预测型机器学习模型(如分类和回归)无疑具有很多优势——例如它们能够捕捉特征之间的非线性关系,以及其直观的可解释性,使得追踪决策变得容易。然而,它们并非完美,尤其是在中等到高复杂度的数据集上训练时,容易出现过拟合、欠拟合或对噪声特征敏感等问题。

在本文中,我们将探讨训练好的决策树模型可能失败的三种常见原因,并概述应对这些问题的简单而有效的策略。文中附有可供您自己尝试的 Python 示例。

1. 过拟合:记住数据而非从数据中学习

Scikit-learn 在构建机器学习模型方面的简便性和直观性可能让人产生“默认构建模型就能得到满意结果”的想法。然而,许多机器学习模型的一个常见问题是过拟合,即模型从数据中学习得过多,以至于几乎记住了所有接触过的数据样本。结果是,当训练好的模型遇到新的、未见过的数据时,它会难以正确预测输出。

下面的示例在流行的公开 California Housing 数据集上训练决策树:该数据集为中等复杂度和规模的回归任务常用数据集,目标是基于人口统计特征和该地区的房屋平均特征,预测加州某地区的房屋中位价。

fromsklearn.datasetsimportfetch_california_housingfromsklearn.model_selectionimporttrain_test_splitfromsklearn.treeimportDecisionTreeRegressorfromsklearn.metricsimportmean_squared_errorimportnumpyasnp# 加载数据集并拆分为训练集和测试集X,y=fetch_california_housing(return_X_y=True,as_frame=True)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=42)# 构建不限制最大深度的决策树overfit_tree=DecisionTreeRegressor(random_state=42)overfit_tree.fit(X_train,y_train)print("Train RMSE:",np.sqrt(mean_squared_error(y_train,overfit_tree.predict(X_train))))print("Test RMSE:",np.sqrt(mean_squared_error(y_test,overfit_tree.predict(X_test))))

注意,这里我们训练了一个基于决策树的回归器,但没有指定任何超参数,包括对树的形状和规模的约束。是的,这会产生影响,即训练样本的误差几乎为零(如下的科学计数法 e-16 所示),而测试集上的误差则远高于训练集。这是过拟合的明显标志。

输出结果:

Train RMSE: 3.013481908235909e-16 Test RMSE: 0.7269954649985176

为了解决过拟合问题,一个常用策略是正则化,即简化模型的复杂度。对于其他模型,这通常涉及较复杂的数学方法,而对于 scikit-learn 中的决策树,则只需限制树的最大深度或叶节点的最小样本数等方面:这两个超参数的设计旨在控制并防止树过度生长。

pruned_tree=DecisionTreeRegressor(max_depth=6,min_samples_leaf=20,random_state=42)pruned_tree.fit(X_train,y_train)print("Train RMSE:",np.sqrt(mean_squared_error(y_train,pruned_tree.predict(X_train))))print("Test RMSE:",np.sqrt(mean_squared_error(y_test,pruned_tree.predict(X_test))))

输出:

Train RMSE: 0.6617348643931361 Test RMSE: 0.6940789988854102

总体而言,第二棵树优于第一棵树,尽管训练集的误差有所增加。关键在于测试数据上的误差,这通常是模型在现实世界中表现的更好指标,而这个误差相较于第一棵树确实有所下降。

2. 欠拟合:树太简单而无法良好工作

与过拟合相反,我们有欠拟合问题,本质上是模型从训练数据中学习不足,即便在训练数据上评估,其表现也低于预期。

过拟合的树通常过于庞大且很深,而欠拟合通常与浅层树结构相关。

解决欠拟合的一种方法是适度增加模型复杂度,同时注意不要过度复杂,从而引发前面讲过的过拟合问题。示例如下(可在 Colab 或类似环境中尝试):

fromsklearn.datasetsimportfetch_openmlfromsklearn.treeimportDecisionTreeRegressorfromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportmean_squared_errorimportnumpyasnp wine=fetch_openml(name="wine-quality-red",version=1,as_frame=True)X,y=wine.data,wine.target.astype(float)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=42)# 树太浅(深度为2)可能导致欠拟合shallow_tree=DecisionTreeRegressor(max_depth=2,random_state=42)shallow_tree.fit(X_train,y_train)print("Train RMSE:",np.sqrt(mean_squared_error(y_train,shallow_tree.predict(X_train))))print("Test RMSE:",np.sqrt(mean_squared_error(y_test,shallow_tree.predict(X_test))))

增加深度以减少误差并缓解欠拟合的版本:

better_tree=DecisionTreeRegressor(max_depth=5,random_state=42)better_tree.fit(X_train,y_train)print("Train RMSE:",np.sqrt(mean_squared_error(y_train,better_tree.predict(X_train))))print("Test RMSE:",np.sqrt(mean_squared_error(y_test,better_tree.predict(X_test))))

3. 误导性的训练特征:引起干扰

决策树对不相关或冗余特征也非常敏感,尤其是在与其他特征一起使用时。这与“信噪比”相关;换句话说,数据中有更多有价值的预测信息(信号)而噪声越少,模型性能越好。

举个例子:一个游客在京都站附近迷路,想去几公里外的清水寺。如果有人告诉她“乘坐 EX101 公交,在五条坂下车,然后沿着上坡的街道走”,她很可能顺利到达目的地;但如果给出的指示是“沿着街道走,转很多弯,记住各种街道名称”,她可能再次迷路。这比喻了像决策树这样的模型中的“信噪比”问题。

谨慎且有策略的特征选择通常是解决此类问题的有效方法。下面这个稍微复杂一些的示例展示了基线树模型、故意在数据集中加入人工噪声以模拟低质量训练数据,以及随后通过特征选择提升模型性能之间的对比。

fromsklearn.datasetsimportfetch_openmlfromsklearn.model_selectionimporttrain_test_splitfromsklearn.treeimportDecisionTreeClassifierfromsklearn.preprocessingimportOneHotEncoderfromsklearn.composeimportColumnTransformerfromsklearn.pipelineimportPipelinefromsklearn.feature_selectionimportSelectKBest,mutual_info_classiffromsklearn.metricsimportaccuracy_scoreimportnumpyasnp,pandasaspd,matplotlib.pyplotasplt adult=fetch_openml("adult",version=2,as_frame=True)X,y=adult.data,(adult.target==">50K").astype(int)cat,num=X.select_dtypes("category").columns,X.select_dtypes(exclude="category").columns Xtr,Xte,ytr,yte=train_test_split(X,y,stratify=y,random_state=42)defmake_preprocessor(df):returnColumnTransformer([("num","passthrough",df.select_dtypes(exclude="category").columns),("cat",OneHotEncoder(handle_unknown="ignore"),df.select_dtypes("category").columns)])# 基线模型base=Pipeline([("prep",make_preprocessor(X)),("clf",DecisionTreeClassifier(max_depth=None,random_state=42))]).fit(Xtr,ytr)print("Baseline acc:",round(accuracy_score(yte,base.predict(Xte)),3))# 添加300个噪声特征,模拟因噪声训练导致的低性能模型rng=np.random.RandomState(42)noise=pd.DataFrame(rng.normal(size=(len(X),300)),index=X.index,columns=[f"noise_{i}"foriinrange(300)])X_noisy=pd.concat([X,noise],axis=1)Xtr,Xte,ytr,yte=train_test_split(X_noisy,y,stratify=y,random_state=42)noisy=Pipeline([("prep",make_preprocessor(X_noisy)),("clf",DecisionTreeClassifier(max_depth=None,random_state=42))]).fit(Xtr,ytr)print("With noise acc:",round(accuracy_score(yte,noisy.predict(Xte)),3))# 解决方案:在管道中使用 SelectKBest() 进行特征选择sel=Pipeline([("prep",make_preprocessor(X_noisy)),("select",SelectKBest(mutual_info_classif,k=20)),("clf",DecisionTreeClassifier(max_depth=None,random_state=42))]).fit(Xtr,ytr)print("After selection acc:",round(accuracy_score(yte,sel.predict(Xte)),3))# 绘制特征重要性importances=noisy.named_steps["clf"].feature_importances_ names=noisy.named_steps["prep"].get_feature_names_out()pd.Series(importances,index=names).nlargest(20).plot(kind="barh")plt.title("Top 20 Feature Importances (Noisy Model)")plt.gca().invert_yaxis()plt.show()

如果一切顺利,经过特征选择后的模型应该产生最佳结果。可以尝试调整特征选择中的 k 值(示例中设为20),观察是否能进一步提升最后模型的性能。

总结

本文中,我们探讨并演示了三种常见问题,这些问题可能导致训练好的决策树模型表现不佳:从欠拟合、过拟合到无关特征。同时,我们展示了应对这些问题的简单而有效的策略。

http://www.jsqmd.com/news/78942/

相关文章:

  • 2025年最后一个月,公司需要注意什么?
  • 可信数据空间:驱动社会高质量发展的“数字基石”,必要性无可替代
  • YashanDB数据库的读写分离策略分析
  • 3步搭建量化投资自动化分析系统:告别Excel手动操作
  • HarmonyOS 5 极致动效实验室:给 UI 注入“物理动效”
  • 自动驾驶汽车与利益相关者互动的功能安全与网络安全分析高效的方法
  • 基于Web的低代码系统的研究与实现中期检查
  • Airflow - AirflowSkipException
  • 2023马士兵Java后端工程师
  • 如何快速实现离线人脸识别:FaceAISDK完整指南
  • springboot基于vue的比亚迪新能源汽车销售系统的设计与实现_1061pdmq
  • springboot基于vue的拜泉县房屋拆迁安置信息管理系统设计与实现_yt2m39o4
  • Nextcloud文件压缩下载实用指南:轻松管理云端文件
  • springboot基于vue的故宫博物馆文创网店商城系统的设计与实现_oj61901i
  • 什么是UUID,怎么组成的?
  • 基于web的电影交流分享平台的设计与实现开题报告
  • YashanDB数据库的多活架构设计及实施要点.
  • Simple Form性能优化完整指南:5个实用技巧让Rails表单快如闪电
  • 基于WEB的多媒体素材管理库的开发与应用任务书
  • springboot基于vue的教师绩效考核系统 年度优秀单位组织评选系统设计与实现_a30c2x4o
  • GPT-5.2 成为“元宇宙”的创世神:虚拟世界的灵魂与下一代沉浸式计算
  • 内网渗透之横向移动持久化远程控制篇——利用ipc、sc、schtasks、AT,远程连接的winrm,wmic的使用和定时任务的创建
  • Vue Flow与Pinia状态管理实战指南:构建高效可视化应用
  • 为什么你的滑动窗口总是写不对?
  • 基于web的二手书交易平台设计与实开题报告
  • Android高斯模糊终极指南:Blurry库完全解析
  • YashanDB数据库的多活架构设计与实施经验分享
  • 计算机毕业设计springboot基于Java的游乐园管理系统设计与实现 基于Spring Boot框架的Java游乐园综合管理系统开发与应用 Java技术驱动的Spring Boot游乐园运营管理系
  • springboot基于vue的春节物资购买平台的设计与实现_88a5r046
  • AMD ROCm平台上的YOLOv8目标检测:从入门到精通的5步优化指南