
简介这份资源面向机器学习入门者与数据挖掘实践者聚焦决策树这一经典监督学习模型帮助读者从原理到代码完整掌握分类与回归任务的实现思路。压缩包共28个文件约2.43MB以10个py脚本和6个ipynb笔记本为核心辅以4份pdf讲义、3个txt说明、2个xlsx数据集及2张png图示兼顾理论讲解与动手实践。内容覆盖ID3、C4.5、CART三大算法的特征选择、节点分裂与剪枝策略并配有员工离职预测案例演示K折交叉验证与GridSearch网格搜索的参数调优流程还涉及graphviz可视化插件的安装使用。已有526人学习适合希望巩固决策树理论、提升建模与调参能力的读者参考。1. 决策树模型源码包从信息熵到员工离职预测的完整落地路径很多做数据挖掘的朋友第一次接触决策树都是在教科书上看到「信息增益」「基尼不纯度」这些概念公式推导看懂了但真到要跑一份能出图、能调参、能解释业务结果的代码时往往卡在环境配置和可视化上。这份「机器学习与算法源代码5决策树模型.zip」就是冲着这个痛点来的——它把决策树从原理推导、案例实战到参数调优串成了一条线配套 Jupyter Notebook 和 PyCharm 两套格式的源码外加一份员工离职预测的真实数据集。适合正在入门机器学习、需要一份能直接跑通的决策树项目练手的人也适合已经会用 sklearn 但想搞清楚 Graphviz 可视化、K 折交叉验证和 GridSearch 网格搜索怎么配合的从业者。下面我按自己拆包复现的顺序把这份资源里真正值得动手的部分讲清楚。2. 拆包先看结构Notebook 与 PyCharm 双格式怎么选2.1 压缩包里的文件分层逻辑拿到压缩包解压后目录大致分成三块源代码汇总_Jupyter Notebook格式、源代码汇总_PyCharm格式以及散落在根目录的 PDF 文档和图片。两套源码的内容是对应的核心文件都是那五个5.1 决策树模型的基本原理、5.2.1 案例实战员工离职预测模型搭建、5.2.2的同名版本、5.3.1 参数调优 - K折交叉验证 GridSearch网格搜索、5.3.2的同名版本。.ipynb和.py的区别在于Notebook 格式把代码、输出结果、Markdown 说明混在一起适合边看边理解PyCharm 格式是纯脚本适合直接改参数跑批量实验。数据文件只有一个员工离职预测模型.xlsx两套源码目录里各放了一份内容一致。可视化相关的辅助文件包括dot_data.txt、dot_data_new.txt、决策树模型.png、决策树模型_new.png以及一份graphviz插件的安装及使用-石墨文档地址.txt和graphviz插件的安装及使用_-_决策树模型可视化.pdf。这些文件说明作者在可视化环节踩过坑专门留了安装说明。提示如果你只是想快速看结果直接打开 Notebook 格式如果要改参数做对比实验用 PyCharm 格式更顺手避免 Notebook 里反复执行单元格导致变量污染。2.2 环境依赖与版本确认这份源码基于 Python 的 sklearn 生态核心依赖是scikit-learn、pandas、numpy、matplotlib可视化部分额外依赖graphviz和 Python 的graphviz包。我一般会先建一个干净虚拟环境避免和系统里已有的包版本打架python -m venv dt_env source dt_env/bin/activate # Windows 用 dt_env\Scripts\activate pip install scikit-learn pandas numpy matplotlib graphviz openpyxl jupyter这里openpyxl容易被忽略但读取.xlsx格式的员工离职数据必须用它否则 pandas 会报Missing optional dependency openpyxl。graphviz这个 pip 包只是 Python 接口系统层面还需要单独安装 Graphviz 软件本体否则画图时会提示ExecutableNotFound: failed to execute [dot]。参数上sklearn 的DecisionTreeClassifier在 0.22 版本之后对criterion的默认值从gini改成了gini没变但splitter默认是best如果你要做随机分裂可以改成random。这些细节在源码的5.1文件里都有注释说明。2.3 两套格式的取舍建议Notebook 格式的优势是每个单元格执行完立刻能看到输出比如5.1里计算信息熵的那段执行后直接打印出熵值方便对照公式理解。但 Notebook 的缺点是变量作用域是全局的如果你先跑了5.2再回头跑5.1X_train、y_train这些变量可能被覆盖导致结果对不上。PyCharm 格式每个脚本独立运行变量隔离适合做参数对比。我的习惯是第一遍用 Notebook 通读原理和案例理解每一步在干什么第二遍用 PyCharm 格式改参数、跑交叉验证、记录不同max_depth下的准确率变化。两套配合用比只盯着一套效率高。3. 决策树原理代码逐段拆信息熵、信息增益与基尼不纯度3.1 信息熵与信息增益的手写实现5.1 决策树模型的基本原理.ipynb里最值得看的是手写信息熵和信息增益的部分。sklearn 把底层计算封装了但如果你不理解熵怎么算调参时看到criterionentropy和criteriongini的差异就只能靠试。源码里有一段计算熵的函数我把它简化后贴出来import numpy as np def calc_entropy(y): 计算数据集 y 的信息熵 n len(y) if n 0: return 0 # 统计每个类别的出现次数 _, counts np.unique(y, return_countsTrue) probs counts / n # 熵 -sum(p * log2(p)) entropy -np.sum(probs * np.log2(probs)) return entropy # 示例一个二分类标签集 y np.array([0, 0, 1, 1, 1, 0, 1, 0]) print(信息熵:, calc_entropy(y))这段代码的逻辑是先统计标签里每个类别的频次转成概率再套用熵公式。np.unique的return_countsTrue参数返回去重后的类别和对应计数比手写循环简洁。参数上np.log2是以 2 为底单位是比特如果你用np.log自然对数单位变成纳特数值会不同但不影响比较大小。信息增益的代码在熵的基础上多了按特征划分的步骤对每个特征计算划分后各子集的加权熵用父节点熵减去它。源码里用了一个循环遍历所有特征选出增益最大的作为分裂节点。这部分手写代码的价值在于你能清楚看到 ID3 算法「选择信息增益最大的特征」这句话在代码层面到底怎么落地。3.2 基尼不纯度与 CART 的分裂逻辑5.1的后半部分讲了基尼不纯度这是 CART 算法默认使用的分裂准则。基尼不纯度的计算比熵简单不需要对数运算def calc_gini(y): 计算基尼不纯度 n len(y) if n 0: return 0 _, counts np.unique(y, return_countsTrue) probs counts / n # 基尼 1 - sum(p^2) gini 1 - np.sum(probs ** 2) return gini对比熵的公式-sum(p * log2(p))基尼不纯度省掉了对数计算所以在数据量大时计算更快。sklearn 的DecisionTreeClassifier默认criteriongini如果你把参数改成entropy分裂准则就切换成信息增益。实际项目中两者结果差异通常不大但基尼不纯度对噪声稍微敏感一些数据干净时用哪个都行。源码里还提到了 CART 处理连续特征的方式对连续值排序后取相邻值的中点作为候选分裂点遍历所有候选点找基尼不纯度最小的那个。这部分在5.1的 Markdown 说明里有公式推导配合代码看能理解为什么决策树对连续特征的处理本质上是「离散化」。3.3 剪枝参数在代码里的对应关系决策树的过拟合是绕不开的问题源码在5.1末尾提到了预剪枝和后剪枝。sklearn 的DecisionTreeClassifier提供的是预剪枝参数常用的有参数含义典型取值max_depth树的最大深度310根据数据量调整min_samples_split节点分裂所需最小样本数220min_samples_leaf叶子节点最小样本数110max_features每次分裂考虑的最大特征数None、sqrt、log2ccp_alpha代价复杂度剪枝参数00.1越大剪枝越狠ccp_alpha是后剪枝的简化实现原理是给每个子树一个惩罚项惩罚项大于收益时就剪掉。源码里没有展开讲这个参数但你在5.3的网格搜索里可以把它加进去一起调。我一般会先固定ccp_alpha0调完max_depth和min_samples_leaf之后再小范围试ccp_alpha避免一开始就剪太狠导致欠拟合。4. 员工离职预测实战从 Excel 读取到模型评估4.1 数据加载与特征工程5.2 案例实战员工离职预测模型搭建.ipynb用的是员工离职预测模型.xlsx这是一份典型的 HR 场景数据包含员工满意度、绩效评分、项目数、月工时、工龄、是否离职等字段。加载数据的代码很直接import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import classification_report, confusion_matrix # 读取 Excel 数据 df pd.read_excel(员工离职预测模型.xlsx) print(df.head()) print(df[离职].value_counts()) # 查看标签分布 # 特征与标签分离 X df.drop(离职, axis1) y df[离职] # 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy )这里有几个参数值得注意test_size0.3表示测试集占 30%random_state42保证每次划分结果一致stratifyy是关键——它让训练集和测试集里离职与未离职的比例和原始数据一致。如果数据里离职样本很少比如只占 5%不加stratify可能导致测试集里一个离职样本都没有评估结果就失真了。源码里还做了简单的特征筛选去掉了员工编号这类无意义的 ID 列。实际项目中如果特征里有类别变量比如部门、职位需要做独热编码但这份数据里大部分是数值型所以直接喂给模型也能跑。4.2 模型训练与可视化出图训练决策树的代码只有几行但可视化部分需要额外配置 Graphviz# 训练决策树 clf DecisionTreeClassifier( criteriongini, max_depth4, min_samples_leaf5, random_state42 ) clf.fit(X_train, y_train) # 预测与评估 y_pred clf.predict(X_test) print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred)) # 导出决策树可视化 from sklearn.tree import export_graphviz import graphviz dot_data export_graphviz( clf, out_fileNone, feature_namesX.columns, class_names[未离职, 离职], filledTrue, roundedTrue, special_charactersTrue ) graph graphviz.Source(dot_data) graph.render(决策树模型) # 生成 PDF 或 PNGexport_graphviz的参数里filledTrue让节点按类别填充颜色roundedTrue让方框变圆角class_names指定类别标签显示中文。graph.render默认生成 PDF如果你想要 PNG可以在graphviz.Source里指定formatpng。源码目录里的决策树模型.png和决策树模型_new.png就是这一步的输出结果。注意如果graph.render报错ExecutableNotFound说明系统没装 Graphviz 软件本体不是 pip 包的问题。Windows 下需要下载 Graphviz 安装包并勾选「Add to PATH」macOS 用brew install graphvizLinux 用apt-get install graphviz。4.3 模型评估指标怎么看classification_report输出的指标里重点看recall召回率和f1-score。在员工离职预测场景下漏掉一个真正要离职的员工假阴性比误判一个不离职的员工假阳性代价更大所以召回率比精确率更重要。源码里没有显式讨论这一点但你在调参时可以把class_weightbalanced加进去让模型对少数类离职样本更敏感。混淆矩阵的四个格子分别对应真阴性预测不离职且实际不离职、假阳性预测离职但实际不离职、假阴性预测不离职但实际离职、真阳性预测离职且实际离职。假阴性就是漏报是 HR 场景里最需要压低的指标。5. 参数调优避坑K 折交叉验证与 GridSearch 的五个翻车点5.1 交叉验证的折数选择与数据泄漏5.3 参数调优 - K折交叉验证 GridSearch网格搜索.ipynb里用的是GridSearchCV配合cv5也就是 5 折交叉验证。折数不是越多越好折数多意味着每折训练集更大评估更稳定但计算时间线性增长。数据量小于 1000 条时用 5 折或 10 折都行数据量上万时 3 折就够再多了收益递减。一个常见的翻车点是数据泄漏如果在交叉验证之前就对整个数据集做了标准化或特征选择那每一折的验证集信息已经泄漏到训练过程里了。正确做法是把预处理放进Pipeline让GridSearchCV在每一折内部单独做预处理。源码里因为特征都是数值型且量纲差异不大没有做标准化所以没踩这个坑但你自己加特征时要注意。5.2 网格搜索的参数空间设置GridSearchCV的核心是param_grid源码里给的参数范围大致是param_grid { max_depth: [3, 4, 5, 6, 7, 8], min_samples_split: [2, 5, 10, 20], min_samples_leaf: [1, 2, 5, 10], criterion: [gini, entropy] } grid_search GridSearchCV( estimatorDecisionTreeClassifier(random_state42), param_gridparam_grid, cv5, scoringf1, n_jobs-1, verbose1 ) grid_search.fit(X_train, y_train) print(最佳参数:, grid_search.best_params_) print(最佳得分:, grid_search.best_score_)参数空间的大小是各参数取值数的乘积6×4×4×2192 种组合每种跑 5 折总共 960 次训练。n_jobs-1让所有 CPU 核心并行跑能显著缩短时间。scoringf1指定用 F1 分数作为评估标准比默认的准确率更适合不平衡数据。verbose1会打印进度但输出量很大调试时可以设成 0。best_score_是交叉验证的平均得分不是测试集得分别混淆。5.3 避坑五个具体翻车记录现象一GridSearchCV跑完best_params_和手动调参结果差很多。原因通常是scoring参数没设对默认用准确率而不平衡数据里准确率高的模型可能只是把所有样本都预测成多数类。解决方法是根据业务目标选scoring离职预测用f1或recall信用评分用roc_auc。现象二交叉验证得分很高但测试集得分低一截。这是过拟合的典型信号说明模型在训练折上表现好但泛化差。解决方法是收紧max_depth或增大min_samples_leaf让树更简单。源码里max_depth的范围到 8实际数据量不大时可能 4 或 5 就够。现象三graph.render生成的图节点太多根本看不清。原因是max_depth没限制树长到了十几层。解决方法是先调好max_depth再出图或者用export_text输出文本版规则比图更易读。现象四pd.read_excel报ImportError。原因是没装openpyxl。解决方法是pip install openpyxl或者把 Excel 另存为 CSV 再用pd.read_csv读取。现象五Notebook 里重复执行单元格导致结果不一致。原因是变量没重置上一次的X_train被覆盖了。解决方法是每次改完代码从Kernel - Restart Run All重新跑一遍保证执行顺序一致。6. 进阶技巧用export_text和ccp_alpha把决策树讲给业务方听决策树最大的优势是可解释性但graphviz出的图在节点多的时候业务方根本看不懂。我一般会先用export_text输出文本规则再挑几条关键路径讲给业务方from sklearn.tree import export_text tree_rules export_text( clf, feature_nameslist(X.columns), max_depth3 # 只显示前 3 层避免规则太长 ) print(tree_rules)export_text的输出是缩进的 if-else 结构比如「如果满意度 0.5 且工龄 2 则预测离职」业务方一看就懂。max_depth3限制显示层数只讲最重要的分裂条件。另一个进阶参数是ccp_alpha它做的是代价复杂度后剪枝。用法是先算出不同ccp_alpha对应的训练集和测试集得分画一条曲线找拐点path clf.cost_complexity_pruning_path(X_train, y_train) ccp_alphas path.ccp_alphas train_scores [] test_scores [] for alpha in ccp_alphas: clf_temp DecisionTreeClassifier(random_state42, ccp_alphaalpha) clf_temp.fit(X_train, y_train) train_scores.append(clf_temp.score(X_train, y_train)) test_scores.append(clf_temp.score(X_test, y_test))cost_complexity_pruning_path返回一系列ccp_alpha值和对应的不纯度从 0 到最大值。ccp_alpha0时不剪枝树最复杂ccp_alpha增大到某个值后整棵树被剪成单节点。拐点通常在测试集得分开始下降之前的位置选那个alpha能让树在保持精度的同时更简洁。我自己的习惯是每次交付决策树模型之前先用export_text把前 3 层规则打印出来确认没有反直觉的分裂条件比如「月工时 200 反而预测不离职」这种再用ccp_alpha剪一遍最后才出图。这套流程走下来业务方质疑「模型为什么这么判」的时候你能直接指着规则解释而不是打开一张密密麻麻的图。从那以后我每次做决策树项目都强制走一遍「文本规则 → 剪枝 → 可视化」这三步省了很多来回扯皮的时间。希望帮到你。本文还有配套的精品资源点击获取