一句话讲完决策树“像做选择题一样一层一层往下问直到得出答案。”写在前面今天讲一个特别直观、特别好懂的算法——决策树Decision Tree。你平时生活里其实天天都在用决策树只是你自己没意识到。比如你去相亲心里会过一遍年龄合不合适→ 长得帅不帅→ 工作好不好→ 见还是不见你买西瓜会敲一敲声音闷不闷→ 瓜蒂新不新鲜→ 皮薄不薄→ 买还是不买决策树就是把这种“一问一答”的决策过程用计算机自动学出来。第一部分决策树是什么1.1 一个真实的小故事银行柜员小张的烦恼小张在银行工作每天要审批信用卡申请。他的判断标准是申请人月收入是否大于8000 ├── 是 → 是否有稳定工作在职满1年 │ ├── 是 → 信用分是否大于650 │ │ ├── 是 → ✅ 批卡额度较高 │ │ └── 否 → ✅ 批卡额度较低 │ └── 否 → ❌ 拒绝 └── 否 → ❌ 拒绝小张的经验就是一棵决策树。1.2 决策树的三个核心概念概念通俗解释对应上面的例子内部节点每个“判断条件”“月收入8000”“在职满1年”分支判断的结果“是 / 否”叶子节点最终结论不再继续分了“✅批卡”或“❌拒绝”1.3 决策树能解决两类问题和KNN一样决策树也是分类回归通吃任务类型预测内容举例分类树预测“是哪一类”信用卡批不批批/拒回归树预测“是多少”批多少额度连续数值5000~10万第二部分决策树的构建流程4步走一颗决策树的“生长”过程分为4步步骤做什么白话解释1特征选择从所有特征里挑一个“最有用”的放在树根2分裂根据这个特征把数据分成两组或多组3递归对分出来的每一组重复步骤1-24停止直到所有叶子节点都“纯”了或者达到设定的停止条件最关键的是第1步——怎么判断哪个特征“最有用”这就是CART算法的核心。第三部分CART决策树最主流的实现3.1 什么是CARTCARTClassification And Regression Tree分类与回归树。它是目前最主流的决策树实现也是随机森林、XGBoost、LightGBM这些高级算法的“地基”。3.2 CART的三个核心规则规则说明举例规则1强制二分每次分裂只能分成两组问“收入8000”→ 是/否不能分成“高/中/低”三组规则2贪心选择每一步都选当前“最有用”的特征比较所有特征选那个让数据分得最“干净”的规则3递归进行一层一层往下分直到满足停止条件分完一组再分下一组像剥洋葱3.3 怎么判断特征“最有用”基尼系数CART分类树用的是基尼系数Gini Index来度量“纯度”。公式pk​ 某组数据中第 k 类样本的比例Gini越小 → 数据越“纯”大家都是一个类Gini越大 → 数据越“混”各类都有一个特征“有用”就是用它划分后两组的Gini系数之和最小分得最干净。3.4 CART回归树预测数值如果我们要预测“批多少额度”连续数字CART也能做。区别在于对比分类树回归树目标预测类别预测数值“纯度”衡量基尼系数Gini均方误差MSE叶子节点输出投票选最多的类别该组所有样本的平均值回归树分裂时找的是让MSE下降最多的那个分裂点。第四部分决策树超参数防过拟合的武器4.1 决策树容易过拟合决策树有个特点如果不加限制它可以一直往下分直到每个叶子节点只剩一个样本。这样的模型在训练集上100%准确但在新数据上表现极差——这就是过拟合。4.2 常用超参数限制树的大小参数作用建议值max_depth树的最大深度层数3~10太深容易过拟合min_samples_split内部节点再划分所需的最小样本数默认2可设5~20min_samples_leaf叶子节点最少样本数默认1可设3~10max_features每次分裂考虑的最大特征数默认全部可设 sqrt(n)4.3 剪枝Pruning——更高级的防过拟合剪枝就是砍掉一些没用的树枝让树变简单。两种剪枝方式方式时机做法优缺点预剪枝树生长过程中每次分裂前评估分了能提升效果吗不能就停省时间但可能“错过好分支”后剪枝树完全长成后从下往上检查这个分支有用吗没用就砍掉效果好但耗时更久sklearn的DecisionTreeClassifier默认是预剪枝——通过max_depth、min_samples_split等参数限制。第五部分信用卡审批预测5.1 生成数据import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score, classification_report import matplotlib.pyplot as plt from sklearn.tree import plot_tree # 设置随机种子 np.random.seed(42) # 生成2000条信用卡申请数据 n 2000 # 特征月收入(万)(0.5~15)、在职月数(1~120)、信用分(300~850)、负债率(0~0.9) income np.random.uniform(0.5, 15, n) work_months np.random.randint(1, 121, n) credit_score np.random.randint(300, 851, n) debt_ratio np.random.uniform(0, 0.9, n) # 生成标签批卡1拒卡0 # 业务逻辑收入高信用分高负债低 → 批卡 score (income * 0.6 credit_score * 0.01 - debt_ratio * 3 work_months * 0.01) y (score 5).astype(int) # 综合得分5批卡 # 拼成DataFrame data pd.DataFrame({ 月收入(万): income, 在职月数: work_months, 信用分: credit_score, 负债率: debt_ratio, 是否批卡: y }) print(数据前5行) print(data.head()) print(f\n总样本数{len(data)}批卡比例{y.sum()/n*100:.1f}%)5.2 划分训练集和测试集决策树不需要标准化# 特征和标签分开 X data[[月收入(万), 在职月数, 信用分, 负债率]] y data[是否批卡] # 训练集70%测试集30% X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42 ) print(f训练集{len(X_train)}条测试集{len(X_test)}条)注意和KNN不同决策树不需要做标准化因为决策树是“按阈值比较”不是算距离特征尺度不影响分裂结果。5.3 训练决策树模型分类# 创建决策树分类器限制深度防止过拟合 model DecisionTreeClassifier( max_depth5, # 最大深度5层 min_samples_split20, # 节点至少20个样本才继续分 min_samples_leaf10, # 叶子节点至少10个样本 random_state42 ) # 训练 model.fit(X_train, y_train) # 预测 y_pred model.predict(X_test) # 准确率 acc accuracy_score(y_test, y_pred) print(f测试集准确率{acc * 100:.2f}%) # 详细分类报告 print(\n分类报告) print(classification_report(y_test, y_pred, target_names[拒卡, 批卡]))5.4 特征重要性分析决策树的隐藏技能决策树能告诉我们哪个特征对决策最重要# 获取特征重要性 importance model.feature_importances_ feature_names [月收入(万), 在职月数, 信用分, 负债率] print(\n特征重要性加起来1) for name, imp in zip(feature_names, importance): print(f {name}{imp:.3f}) # 可视化特征重要性 plt.figure(figsize(8, 5)) plt.barh(feature_names, importance, colorsteelblue) plt.xlabel(重要性) plt.title(信用卡审批决策树-特征重要性) plt.show()输出示例特征重要性加起来1 月收入(万)0.452 在职月数0.098 信用分0.335 负债率0.115说明月收入和信用分是最关键的两个因素。5.5 可视化决策树画出来看看plt.figure(figsize(25, 15)) plot_tree( model, feature_namesfeature_names, class_names[拒卡, 批卡], filledTrue, # 用颜色表示类别 roundedTrue, # 圆角框 fontsize12, max_depth4 # 只画前4层不然太密 ) plt.title(信用卡审批决策树) plt.show()5.6 决策树回归预测授信额度如果把标签改成连续值批多少额度就是用回归树。from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import mean_squared_error, mean_absolute_error # 生成新的标签授信额度万范围2~50 limit 2 income * 2.5 credit_score * 0.02 - debt_ratio * 10 np.random.normal(0, 2, n) limit np.clip(limit, 2, 50) # 重新切分 X_train, X_test, y_train_reg, y_test_reg train_test_split( X, limit, test_size0.3, random_state42 ) # 创建回归树 reg_model DecisionTreeRegressor( max_depth6, min_samples_split20, min_samples_leaf10, random_state42 ) # 训练 reg_model.fit(X_train, y_train_reg) # 预测 y_pred_reg reg_model.predict(X_test) # 评估 mse mean_squared_error(y_test_reg, y_pred_reg) mae mean_absolute_error(y_test_reg, y_pred_reg) print(f回归树 - 均方误差(MSE){mse:.2f}) print(f回归树 - 平均绝对误差(MAE){mae:.2f}) print(f真实额度前5个{y_test_reg[:5]}) print(f预测额度前5个{y_pred_reg[:5]})第六部分决策树 vs KNN什么时候用谁对比维度决策树KNN是否需要标准化❌ 不需要✅ 必须做可解释性✅ 超强可以画出来看❌ 黑盒训练速度✅ 快❌ 慢要存所有数据预测速度✅ 极快就几层判断❌ 慢要算距离对缺失值处理可以处理无法处理过拟合风险高需要剪枝低调K值就好非线性数据✅ 能处理❌ 效果差经验建议需要解释给老板/客户听→ 选决策树可以画图展示数据特征少、干净→ 选KNN数据有缺失值→ 选决策树追求预测速度在线服务→ 选决策树追求极致准确率→ 两个都试试选好的第七部分CART的优缺点7.1 优点5个优点说明简单易懂画出来一看就懂非技术人员也能理解功能强大分类回归通吃规则简洁强制二分逻辑清晰鲁棒性好自带剪枝抗过拟合应用广泛是随机森林、XGBoost的基石7.2 缺点3个缺点说明容易过拟合不加限制的话可以完美拟合训练集结果不稳定数据稍微变一点整棵树可能完全不一样非全局最优每一步只选当前最优贪心不保证整体最优第八部分剪枝详解两种方式对比8.1 预剪枝Pre-pruning在树生长过程中就决定“要不要继续分”。# 这就是预剪枝——通过参数限制树的生长 model DecisionTreeClassifier( max_depth5, # 到5层就不分了 min_samples_split20, # 样本少于20就不分了 min_samples_leaf10 # 叶子少于10就不分了 )优点缺点省时间不用长完整棵树可能“短视”——现在没用但后面有用的分支被误砍防止过拟合容易欠拟合8.2 后剪枝Post-pruning先让树完全长成再从下往上检查这个分支有用吗没用就砍掉。sklearn的DecisionTreeClassifier的ccp_alpha参数可以实现成本复杂度剪枝一种后剪枝。# 用ccp_alpha做后剪枝值越大剪得越狠 model_pruned DecisionTreeClassifier( ccp_alpha0.005, # 剪枝系数需要调参 random_state42 ) model_pruned.fit(X_train, y_train)优点缺点比预剪枝效果好保留了更多有用分支耗时先要长完整棵树实战建议先用预剪枝限制max_depth等简单高效如果效果还不够好再尝试后剪枝。第九部分完整知识点脑图决策树CART │ ├── 核心思想 │ └── 像做选择题一样一层层往下问直到出答案 │ ├── 三大规则 │ ├── 强制二分每次只分两组 │ ├── 贪心选择每一步选最纯的特征 │ └── 递归进行一层一层往下分 │ ├── 两种任务 │ ├── 分类树基尼系数衡量纯度 │ └── 回归树MSE衡量纯度叶子输出平均值 │ ├── 防止过拟合 │ ├── 预剪枝限深度、限样本数← sklearn默认 │ └── 后剪枝先长完整棵树再砍← ccp_alpha │ ├── 优势 │ ├── 可解释性强可以画图 │ ├── 不需要标准化 │ └── 能处理缺失值 │ └── 劣势 ├── 容易过拟合 ├── 结果不稳定数据一变树就变 └── 贪心策略不保证全局最优第十部分总结模块核心内容决策树思想一层一层做选择题直到得出结论CART算法强制二分 基尼系数 递归分裂分类 vs 回归分类看基尼回归看MSE超参数max_depth、min_samples_split等防过拟合剪枝预剪枝生长时限制和后剪枝长完再砍对比KNN决策树可解释性强、不需标准化、速度快代码实战信用卡审批预测分类 额度预测回归给新手的3个建议先理解“树是怎么长的”每次找一个特征分裂→让数据变纯→递归→停止。把这句话背下来决策树的骨架你就有了。重视max_depth这个参数它是防止过拟合最简单粗暴的手段。从max_depth3开始试慢慢加深。画图看树plot_tree是你理解模型最好的工具。画出来一看比看100行代码都管用。