资讯动态

决策树分类实验报告高分指南:从西瓜数据集到可复现的机器学习大作业

发布时间:2026/10/14 7:19:08 来源:尧图企业网站定制
简介这份资源是一份面向高校机器学习课程学习者的决策树分类算法实验报告以毒蘑菇数据集分类为核心案例适合正在完成课程大作业或需要撰写规范实验报告的学生参考。压缩包内仅含1个docx文档大小约1.21MB内容涵盖研究意义、数据描述、模型描述、算法实现、运行结果及总结等完整章节并配有算法流程图与伪代码说明。实验基于UCI Mushroom数据集包含8124个样本、22个原始特征经预处理扩展至117维采用ID3与CART两种特征选择策略结合后剪枝优化并通过混淆矩阵计算准确率、精度与召回率重点讨论食用物分类中召回率的重要性。目前已有7564人学习下载读者可借此掌握决策树从数据预处理、特征选择到模型评估的完整流程理解信息增益与基尼不纯度的差异并直接借鉴报告结构与实验分析思路高效完成同类大作业。1. 决策树分类实验报告从西瓜数据集到可复现的高分作业很多人做机器学习决策树分类算法实验报告最后交上去的是一份“跑通了但说不清”的文档代码能出图准确率也还行可老师一问“为什么选信息增益而不是基尼指数”“剪枝参数怎么定的”就答不上来。这篇笔记就围绕决策树分类器这个核心把一份能拿高分的机器学习大作业拆成可复现的步骤。适合正在做机器学习课程设计、期末大作业或者刚入门想搞懂决策树算法到底怎么落地的人。我会用经典的西瓜数据集和一份真实表格数据两条线把数据处理、建模、调参、可视化、报告撰写串起来重点讲清楚每个参数背后的含义和容易翻车的地方。读完你能自己从头搭一套决策树分类流程并且知道报告里该写什么才显得“真做过”。2. 决策树分类算法实验报告的技术底座原理、选型与数据准备2.1 决策树分类器到底在做什么决策树分类器的本质是一连串 if-else 规则的集合。它从根节点开始每次选一个特征对样本进行划分直到叶子节点给出类别。和逻辑回归、SVM 相比决策树最大的优势是可解释性强——你可以直接把树画出来告诉别人“纹理清晰且触感硬滑的就是好瓜”。这在实验报告里是极大的加分项因为老师能直观看到你的模型学到了什么。但决策树也有明显的短板不加限制会无限生长把训练集里每个样本都单独分到一个叶子导致过拟合。所以实验报告里必须体现你对预剪枝和后剪枝的理解。常见做法是用max_depth、min_samples_split、min_samples_leaf这些参数控制树的复杂度而不是等它长完再剪。我一般会在报告里先展示一棵不加限制的树有多深再对比剪枝后的树用数据说明泛化能力的变化。另一个关键点是划分标准。ID3 用信息增益C4.5 用信息增益率CART 用基尼指数。scikit-learn 默认是 CART也就是基尼指数。很多同学报告里写“用了信息增益”但代码里调的是criteriongini这是典型的自相矛盾。你至少要解释清楚基尼指数计算不涉及对数速度更快信息增益对取值多的特征有偏好。选哪个不是拍脑袋要结合数据特征数量和计算开销来说。2.2 实验数据准备从西瓜数据集到通用表格西瓜数据集是周志华《机器学习》里的经典数据共 17 个样本特征包括色泽、根蒂、敲声、纹理、脐部、触感标签是好瓜/坏瓜。这个数据集小适合演示原理但直接拿来做大作业会显得单薄。我的建议是用西瓜数据集讲清楚原理再用一份更大的真实数据做完整实验。比如 UCI 的 Bank Marketing 数据集或者 Kaggle 的 Titanic样本量在几千条特征有数值有类别能体现完整的数据处理流程。数据处理部分要写清楚三件事缺失值怎么处理、类别特征怎么编码、数值特征要不要离散化。决策树对缺失值敏感scikit-learn 的决策树不支持缺失值所以必须填充。常见做法是数值特征用中位数填充类别特征用众数填充。类别编码用OrdinalEncoder或OneHotEncoder但要注意决策树基于特征取值划分OneHot 之后每个类别单独成列树可能会过度偏向某个类别。我一般对有序类别用 OrdinalEncoder对无序类别用 OneHotEncoder并在报告里说明理由。下面是一段完整的数据准备代码以西瓜数据集为例展示从原始表格到可训练特征的流程import pandas as pd import numpy as np from sklearn.preprocessing import OrdinalEncoder from sklearn.model_selection import train_test_split # 西瓜数据集3.0手动录入 data { 色泽: [青绿,乌黑,青绿,青绿,乌黑,青绿,乌黑,乌黑,乌黑,青绿,青绿,青绿,青绿,乌黑,青绿,青绿,乌黑], 根蒂: [蜷缩,蜷缩,蜷缩,蜷缩,蜷缩,稍蜷,稍蜷,稍蜷,稍蜷,硬挺,硬挺,蜷缩,稍蜷,稍蜷,蜷缩,蜷缩,蜷缩], 敲声: [浊响,沉闷,浊响,浊响,浊响,浊响,浊响,浊响,沉闷,清脆,清脆,浊响,浊响,浊响,浊响,浊响,沉闷], 纹理: [清晰,清晰,清晰,清晰,清晰,清晰,稍糊,清晰,稍糊,清晰,模糊,模糊,稍糊,稍糊,清晰,模糊,稍糊], 脐部: [凹陷,凹陷,凹陷,凹陷,凹陷,稍凹,稍凹,稍凹,稍凹,平坦,平坦,平坦,凹陷,稍凹,稍凹,平坦,稍凹], 触感: [硬滑,硬滑,硬滑,硬滑,硬滑,软粘,软粘,硬滑,硬滑,硬滑,软粘,软粘,硬滑,软粘,硬滑,硬滑,软粘], 好瓜: [是,是,是,是,是,是,是,是,否,否,否,否,否,否,否,否,否] } df pd.DataFrame(data) # 类别特征编码有序类别用OrdinalEncoder # 注意这里为了演示统一用OrdinalEncoder实际报告要说明每个特征的有序性 encoder OrdinalEncoder() feature_cols [色泽,根蒂,敲声,纹理,脐部,触感] df[feature_cols] encoder.fit_transform(df[feature_cols]) X df[feature_cols] y df[好瓜].map({是:1, 否:0}) # 划分训练集和测试集因为样本少用分层抽样保证类别比例 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) print(f训练集大小{X_train.shape}测试集大小{X_test.shape})这段代码的逻辑是先把原始表格转成 DataFrame然后用 OrdinalEncoder 把类别映射成整数。这里有个细节——OrdinalEncoder默认按字母顺序编码但西瓜数据集的特征是有序的比如“纹理”的清晰 稍糊 模糊直接按字母顺序会打乱顺序。更严谨的做法是手动指定categories参数按业务顺序排列。代码最后用stratifyy做分层抽样因为西瓜数据集正负样本比例是 8:9分层能保证训练集和测试集里好瓜坏瓜的比例一致。参数random_state42是为了结果可复现实验报告里必须固定随机种子否则每次跑出来的树都不一样没法写结论。2.3 划分标准的选择信息增益、增益率与基尼指数实验报告里必须有一节专门对比划分标准。很多同学只写“用了基尼指数”但不解释为什么。你可以设计一个小实验在同一份数据上分别用criteriongini和criterionentropy训练对比树的结构和测试准确率。通常两者差异不大但熵的计算更慢。如果数据特征取值很多基尼指数更稳定。信息增益的公式是Gain(D,a) Ent(D) - Σ (|Dv|/|D|) * Ent(Dv)它倾向于选择取值多的特征。比如给每个样本一个唯一 ID信息增益会最大但这样的划分没有泛化意义。增益率在信息增益基础上除以特征固有值IV(a) -Σ (|Dv|/|D|) log2(|Dv|/|D|)缓解了偏好问题。CART 用的基尼指数Gini(D) 1 - Σ pk^2计算更简单。在报告里我一般会放一张对比表划分标准公式核心偏好计算开销适用场景信息增益熵减取值多的特征中ID3特征取值少增益率增益/固有值取值少的特征高C4.5混合类型特征基尼指数不纯度无明显偏好低CART大规模数据这张表能让老师看到你不是只会调库而是理解背后的权衡。注意scikit-learn 只支持基尼指数和熵不支持增益率。如果你报告里写“用 C4.5 算法”但代码是DecisionTreeClassifier(criterionentropy)严格来说这是 ID3 的变体不是完整的 C4.5。要么改说法要么自己实现增益率。3. 用 scikit-learn 跑通决策树分类建模、调参与可视化3.1 最小可运行建模流程有了处理好的数据下一步就是训练决策树。scikit-learn 的DecisionTreeClassifier封装得很好但参数不少每个都影响树的结构。先看一段最小可运行代码from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score, classification_report # 初始化决策树先不加限制看看树能长多深 clf DecisionTreeClassifier(random_state42) clf.fit(X_train, y_train) # 预测并评估 y_pred clf.predict(X_test) print(f训练集准确率{clf.score(X_train, y_train):.4f}) print(f测试集准确率{clf.score(X_test, y_test):.4f}) print(f树的最大深度{clf.get_depth()}) print(f叶子节点数{clf.get_n_leaves()}) print(classification_report(y_test, y_pred))这段代码先训练一棵不加限制的树。在西瓜数据集上你大概率会看到训练集准确率 100%测试集准确率可能只有 60% 左右树深度 5 到 6 层。这就是典型的过拟合。实验报告里要把这个结果放进去作为“未剪枝”的基线然后引出调参的必要性。classification_report会输出精确率、召回率、F1 值。对于类别不平衡的数据准确率有欺骗性必须看 F1。比如坏瓜占多数模型全预测坏瓜也能有高准确率但好瓜的召回率是 0。报告里要解释每个指标的含义别只贴数字。3.2 预剪枝参数怎么调max_depth、min_samples_split、min_samples_leaf预剪枝是在树生长过程中提前停止。scikit-learn 提供了几个关键参数max_depth树的最大深度。默认 None表示不限。一般从 3 开始试逐步增加。min_samples_split节点分裂所需的最小样本数。默认 2太小容易过拟合。可以设成 5 到 20。min_samples_leaf叶子节点最少样本数。默认 1设成 3 到 10 能防止孤立样本。max_features每次分裂考虑的最大特征数。默认 None即全部特征。特征多时可以设sqrt或log2。ccp_alpha代价复杂度剪枝参数用于后剪枝。默认 0值越大树越简单。调参不能靠猜要用网格搜索或学习曲线。下面是一段用GridSearchCV调参的代码from sklearn.model_selection import GridSearchCV # 定义参数网格 param_grid { max_depth: [2, 3, 4, 5, 6, None], min_samples_split: [2, 5, 10, 20], min_samples_leaf: [1, 3, 5, 10], criterion: [gini, entropy] } # 5折交叉验证 grid GridSearchCV( DecisionTreeClassifier(random_state42), param_grid, cv5, scoringf1, n_jobs-1 ) grid.fit(X_train, y_train) print(f最佳参数{grid.best_params_}) print(f最佳交叉验证F1{grid.best_score_:.4f}) print(f测试集准确率{grid.score(X_test, y_test):.4f})这段代码用 5 折交叉验证在训练集上找最优参数评分用 F1 而不是准确率因为类别可能不平衡。n_jobs-1表示用所有 CPU 核心并行。跑完后best_params_会给出最佳组合。注意网格搜索是在训练集上做的测试集只用来最终评估不能拿测试集调参否则就是数据泄露。在西瓜数据集上最佳max_depth通常是 3 或 4min_samples_leaf是 1 或 2。因为样本太少参数太大会欠拟合。如果换成 Bank Marketing 这种几千条的数据min_samples_leaf可以设到 10 以上。报告里要写清楚参数取值和数据规模强相关不能照搬。3.3 后剪枝用 ccp_alpha 做代价复杂度剪枝预剪枝有个问题有些分支当前看起来没用但后续可能带来性能提升预剪枝会误杀。后剪枝先让树长完再自底向上剪掉不划算的子树。scikit-learn 用ccp_alpha控制剪枝强度值越大剪得越狠。找最佳ccp_alpha的方法是画剪枝路径import matplotlib.pyplot as plt # 获取剪枝路径 path clf.cost_complexity_pruning_path(X_train, y_train) ccp_alphas path.ccp_alphas impurities path.impurities # 训练不同alpha的树 clfs [] for alpha in ccp_alphas: clf_alpha DecisionTreeClassifier(random_state42, ccp_alphaalpha) clf_alpha.fit(X_train, y_train) clfs.append(clf_alpha) # 画图alpha vs 准确率 train_scores [c.score(X_train, y_train) for c in clfs] test_scores [c.score(X_test, y_test) for c in clfs] plt.figure(figsize(8, 5)) plt.plot(ccp_alphas, train_scores, markero, label训练集) plt.plot(ccp_alphas, test_scores, markers, label测试集) plt.xlabel(ccp_alpha) plt.ylabel(准确率) plt.legend() plt.title(代价复杂度剪枝路径) plt.show()这段代码先调用cost_complexity_pruning_path得到一系列 alpha 值然后对每个 alpha 训练一棵树记录训练集和测试集准确率。图上通常能看到alpha 很小时训练集准确率高、测试集低alpha 增大到某个点测试集准确率最高再大就欠拟合。报告里要标出这个最优点并解释为什么选它。注意ccp_alpha和max_depth可以一起用但一般选一种就行。如果报告里同时用预剪枝和后剪枝要说明各自的作用别让老师觉得你在堆参数。3.4 决策树可视化把 if-else 规则画出来决策树最大的优势是可解释所以实验报告里一定要有可视化。scikit-learn 提供了plot_tree但图大了会糊。更好的做法是用 Graphviz 导出 PDF或者用dtreeviz库画更漂亮的图。from sklearn.tree import plot_tree import matplotlib.pyplot as plt # 用最佳参数重新训练 best_clf DecisionTreeClassifier( max_depth3, min_samples_leaf2, random_state42 ) best_clf.fit(X_train, y_train) # 可视化 plt.figure(figsize(12, 8)) plot_tree( best_clf, feature_namesfeature_cols, class_names[坏瓜, 好瓜], filledTrue, roundedTrue, fontsize10 ) plt.title(决策树可视化max_depth3) plt.show()plot_tree的参数含义feature_names显示特征名class_names显示类别名filledTrue按类别填充颜色roundedTrue圆角框。生成的图里每个节点会显示划分条件、基尼指数、样本数、类别分布。报告里要解读这棵树根节点用了哪个特征为什么第二层怎么分叶子节点纯不纯如果树太深plot_tree会看不清可以只画前几层或者用max_depth限制。另外Graphviz 的export_graphviz能导出更专业的图但需要安装 Graphviz 软件报告里可以附上安装命令。4. 实验报告里最容易翻车的五个坑4.1 数据泄露在划分训练集之前做了标准化或编码现象测试集准确率异常高接近 100%但换一份数据就崩。原因很多同学先把整个数据集做标准化或编码再划分训练集和测试集。这样测试集的统计信息均值、方差、类别分布泄露到了训练过程。决策树虽然对标准化不敏感但编码和缺失值填充会泄露。解决先train_test_split再在训练集上fit编码器或填充器然后transform测试集。用Pipeline能避免这个错误from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer from sklearn.preprocessing import OrdinalEncoder pipe Pipeline([ (imputer, SimpleImputer(strategymost_frequent)), (encoder, OrdinalEncoder()), (clf, DecisionTreeClassifier(random_state42)) ]) pipe.fit(X_train, y_train)4.2 用测试集调参然后报告测试集准确率现象报告里写“经过调参测试集准确率达到 95%”但老师一问调参过程就露馅。原因把测试集当成验证集用反复在测试集上试参数相当于让模型“见过”测试集。最终报告的准确率是乐观偏差。解决训练集再划分出验证集或者用交叉验证。测试集只在最后评估一次。报告里要写清楚调参用交叉验证测试集从未参与调参。4.3 忽略类别不平衡只看准确率现象准确率 90%但少数类召回率 0%。原因数据里正负样本比例悬殊模型全预测多数类就能拿高准确率。决策树虽然比朴素贝叶斯好一点但也会偏向多数类。解决用class_weightbalanced让模型关注少数类或者用 F1、AUC 作为评估指标。报告里要同时给出混淆矩阵和分类报告。4.4 树太深导致过拟合却归因于“数据噪声”现象训练集 100%测试集 60%报告里写“数据存在噪声模型泛化能力有限”。原因没有剪枝树把训练集里每个样本的细节都学到了包括噪声。这不是数据的问题是模型复杂度的问题。解决限制max_depth、min_samples_leaf或者用ccp_alpha后剪枝。报告里要对比剪枝前后的树深度和测试准确率用数据说明剪枝有效。4.5 特征编码顺序错误导致树的分裂逻辑反了现象可视化出来的树根节点分裂条件看起来不合理比如“纹理 1.5”把清晰和模糊分到一边。原因OrdinalEncoder默认按字母顺序编码但特征本身是有序的。比如“纹理”的清晰、稍糊、模糊字母顺序是“模糊、清晰、稍糊”编码后 0模糊1清晰2稍糊完全打乱了业务顺序。解决手动指定categories参数按业务顺序排列encoder OrdinalEncoder(categories[ [模糊, 稍糊, 清晰], # 纹理从差到好 [平坦, 稍凹, 凹陷], # 脐部 [软粘, 硬滑], # 触感 [清脆, 沉闷, 浊响], # 敲声 [硬挺, 稍蜷, 蜷缩], # 根蒂 [乌黑, 青绿, 浅白] # 色泽 ])报告里要说明每个特征的编码顺序和业务含义别让老师猜。5. 让实验报告更有说服力的进阶技巧学习曲线与特征重要性5.1 用学习曲线判断过拟合还是欠拟合学习曲线横轴是训练集大小纵轴是准确率画两条线训练集得分和验证集得分。如果两条线中间有大间隙说明过拟合如果两条线都很低且接近说明欠拟合。代码很简单from sklearn.model_selection import learning_curve import numpy as np train_sizes, train_scores, test_scores learning_curve( DecisionTreeClassifier(max_depth3, random_state42), X, y, cv5, scoringf1, train_sizesnp.linspace(0.1, 1.0, 10) ) train_mean np.mean(train_scores, axis1) test_mean np.mean(test_scores, axis1) plt.figure(figsize(8, 5)) plt.plot(train_sizes, train_mean, o-, label训练集F1) plt.plot(train_sizes, test_mean, s-, label验证集F1) plt.xlabel(训练样本数) plt.ylabel(F1) plt.legend() plt.title(学习曲线) plt.show()在西瓜数据集上因为样本只有 17 条学习曲线会很抖验证集 F1 波动大。这本身就是一个结论数据量太小模型评估不可靠。报告里可以建议收集更多数据或者用交叉验证的均值±标准差来报告结果。5.2 特征重要性哪些特征对分类贡献最大决策树自带feature_importances_属性返回每个特征的重要性分数总和为 1。这个分数基于分裂带来的不纯度减少量。代码import pandas as pd best_clf DecisionTreeClassifier(max_depth3, random_state42) best_clf.fit(X_train, y_train) importance pd.DataFrame({ 特征: feature_cols, 重要性: best_clf.feature_importances_ }).sort_values(重要性, ascendingFalse) print(importance)在西瓜数据集上纹理的重要性通常最高其次是根蒂和色泽。报告里要结合业务解释纹理清晰的好瓜概率大这和“敲声浊响、根蒂蜷缩”等特征有相关性。但要注意特征重要性对 correlated 特征会分散分数不能直接说“某个特征不重要”。如果两个特征高度相关树可能随机选一个另一个重要性就低。5.3 报告结构建议老师想看到什么一份高分实验报告通常包含问题定义、数据描述、数据预处理、方法原理、实验设置、结果分析、结论。其中结果分析是拉开差距的地方。不要只贴准确率要对比不同参数、不同划分标准、剪枝前后的差异用表格和图表说话。比如配置训练集F1测试集F1树深度叶子数无剪枝1.0000.60067max_depth30.9000.80034ccp_alpha0.020.8500.80034这张表能直观展示剪枝的效果。最后用第一人称写一句我一般会在报告最后附上完整代码和随机种子确保别人能复现我的结果。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑