资讯动态

对率回归决策树:原理、手写实现与常见坑

发布时间:2026/10/3 4:23:16 来源:尧图企业网站定制
简介面向机器学习初学者的对率回归决策树Python实现以经典西瓜数据集3.0为实验对象调用sklearn.linear_model中的LogisticRegression完成模型训练。程序先将字符串型属性数值化对连续属性进行离散化再以分类正确率为准则为每个属性打分选择得分最高者作为根节点并对该节点每个属性取值递归划分最终生成决策树数组通过绘图函数输出树形图片直观呈现完整分类逻辑。压缩包共4个文件包括2个Python脚本——分别承担对率回归决策树建模与树形图绘制功能1个txt格式的西瓜数据集以及1张示例输出png整体大小仅362KB轻量简洁便于在课程实验或毕业设计中快速复用。目前已有2841人学习下载具备一定参考价值。读者可仿照流程替换自己的离散数据集观察对率回归与信息增益在划分策略上的差异同时掌握基于正确率构建决策树的基本方法是一份兼顾理论演示与动手实践的机器学习入门资源。1. 对率回归决策树是什么名字里的两个坑以及它到底解决什么问题第一次在《机器学习》西瓜书里看到「对率回归」这四个字的人十有八九会愣一下这不是逻辑回归吗再看「对率回归决策树」更懵决策树怎么做回归这两个名字叠在一起像是一道期末送命题。先把话说清楚对率回归就是周志华老师对逻辑回归Logistic Regression的译法它对着的是「对数几率」这个量对率回归决策树则是一棵叶子节点上长着逻辑回归模型的分类树——树负责把特征空间切成矩形区域每个区域里再拟合一条线性决策边界。它解决的是两个具体痛点普通决策树输出是分段常数逼近真实曲线全靠无限切分切深了就过拟合纯逻辑回归又是全局线性模型面对非线性边界时只能靠手工特征工程硬凑。适合读这篇的人有三类西瓜书读者和期末复习党被头歌平台的决策树作业折腾到想自己写一遍的人以及已经把 sklearn 的树和回归用熟了、想看看「树 叶子局部模型」这种混合结构到底怎么实现的人。下面从原理一路讲到代码和踩坑。2. 为什么决策树要长出对率回归从分段常数到分段平滑2.1 决策树如何逼近真实曲线一刀一刀砍出来的阶梯先看一棵标准 CART 分类树在干什么。它每做一次切分就沿着某个特征的某个阈值把当前节点里的样本分成左右两堆。递归切下去最终每个叶子节点给出一个输出分类场景下通常是多数类或者各类别占比。这个输出是离散的意味着整棵树的决策边界是「平行于坐标轴的一段一段直线」预测函数是一个阶梯函数。在二维数据上这个特征非常明显。拿make_moons那种弯月形边界来说真实边界是光滑曲线决策树怎么逼近它答案是砍更多刀。深度 2 的树只能切出 4 个矩形区域边界粗糙深度 8 的树能切出上百个小格子边界看起来「像」曲线了但每个格子内部依然是硬编码的类别或概率常数。也就是说决策树对真实曲线的逼近方式是「用分段常数去怼光滑函数」像用乐高积木搭一个圆块越小越像但永远不平滑。这个特性的直接后果有两个。第一预测概率是折线台阶状的样本在同一个叶子内移动预测概率完全不变一旦跨过切分边界概率突然跳变。很多业务场景需要平滑的置信度这种跳变很难看。第二树深了以后样本被切得越来越碎叶子里的样本量骤减统计意义下降泛化能力随之崩掉。这也是为什么调参时max_depth和min_samples_leaf永远是一对矛盾想逼近曲线就得加深加深就过拟合。这里有一个常见的误解要纠正很多人以为决策树「逼近真实曲线」靠的是模型本身有连续表达能力其实它靠的是资源堆砌。对率回归决策树换了一个思路——树不需要把边界切到完美只要把空间切到「每个区域内部可以用一条直线近似」就行剩下的精细拟合交给叶子里的逻辑回归。这是一个分工问题。2.2 逻辑回归为什么单独搞不定非线性边界逻辑回归对率回归的数学形式很简洁对每个样本 x模型计算线性组合w·x b再经过 sigmoid 函数映射到 0 到 1 之间。它的决策边界天然就是超平面——二维里是直线三维里是平面。这个特性既是优点也是天花板全局光滑、可解释性极强、训练极快但面对非线性边界时它只能做一条直线永远无法拟合弯月形的分类边界。有人会说那我加多项式特征不就行了确实可以比如把x1^2、x1*x2这种交互项加进去线性边界在原始特征空间里也能变成曲线。但问题在于你并不知道该加哪些项、加几次方。数据维度一旦上去手动做特征工程就是玄学而且多项式扩展会把特征空间撑得很大带来严重的共线性和计算浪费。更深一层的问题在于「全局假设」。逻辑回归假设整个特征空间里正负样本可以用同一个线性边界分开。这个假设在真实数据里过于奢侈现实数据往往是「这个区域里正样本多那个区域里负样本多」每个区域的方向都不一样。与其让一个全局线性模型硬扛所有区域不如让每个区域各自拥有一个局部线性边界。对率回归决策树就是这种「局部线性」思想的直接落地决策树做分区每个分区内独立训练一个逻辑回归不同分区可以有不同的 w 和 b——这才是「对率回归 决策树」组合的真正意义。2.3 混合模型的分工树负责分区回归负责区内拟合把前面两个小节合起来看对率回归决策树的架构就非常清晰了。它是一个两阶段模型第一阶段决策树递归切分特征空间。切分准则仍然是传统的纯度指标基尼系数或信息熵目标是让每个叶子区域内的样本尽量「可分」——注意是「尽量可分」不是「完全纯净」。因为后面还有逻辑回归兜底。第二阶段在每个叶子节点内部收集落到该叶子的训练样本独立训练一个逻辑回归模型。这个回归模型负责刻画该区域内部的局部决策边界并输出一个连续的概率值。这个结构与随机森林的本质区别要拎清楚。随机森林是 Bagging 思路训练多棵树每棵树独立预测最后投票。对率回归决策树只有一棵树它不集成多棵树而是把一棵树的每个叶子当成一个「微型分类器容器」。它和「先用树做特征工程、再把叶子编码喂给逻辑回归」的做法也不同——后者是把树当成特征变换器整棵树的输出拼接成一个稀疏向量对率回归决策树则是每个区域单独建模互不共享参数。这种分工带来的收益是什么第一决策边界从阶梯状变成分段折线树给出矩形分区每个分区内逻辑回归给出连续概率整体预测函数是分段光滑的比纯决策树更接近真实曲线。第二缓解了深度与样本碎片化的矛盾树不需要切得很深因为叶子内部不再用少数样本投票而是用局部线性模型拟合即使某个叶子只有几十个样本拟合一个二维逻辑回归也足够了。第三保留了可解释性每个叶子都能打印出它的 w 和 b你能直接看到「这个区域里哪个特征主导了决策方向」。这个特性是深层神经网络给不了的。3. 用 Python 手写一个对率回归决策树从数据生成到递归切分3.1 最小可运行的数据与评估基准先准备一份能立刻看到效果的数据。用make_moons生成弯月形二分类数据是这类模型最合适的起点——它有明显的非线性边界、自带噪点、维度低画图直观而且恰好能把「决策树阶梯边界」和「分段线性边界」的差异展示出来。import numpy as np from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split X, y make_moons(n_samples600, noise0.2, random_state42) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42 ) print(X_train.shape, y_train.mean())逻辑说明make_moons生成 600 个二维样本noise0.2控制类别边界上的噪点强度越大越难分。按 7:3 划分训练集和测试集评估基准就两个测试集准确率以及后面要画的决策边界图。mean()看一眼正负样本比例确认不是严重不均衡数据。参数说明random_state42固定随机种子保证每次跑出来的数据和后续实验结果一致——这一步在写课程作业或做对比实验时是必须的否则你调参调了半天换一次随机种子结论就变了。noise不要拉太高0.15~0.25 之间比较合适太高了逻辑回归在叶子内部也学不到稳定边界。3.2 树结构定义把「叶子参数」设计进节点手写实现时最容易翻车的地方是数据结构设计。如果你把树节点和叶子模型分开存成两个列表后面递归预测时要靠索引对齐一旦树结构变了索引就乱。我一般这样做树节点本身就是一个可递归的类叶子模型直接挂在节点上。class TreeNode: def __init__(self): self.split_feature None # 切分特征下标 self.split_threshold None # 切分阈值 self.left None # 左子树 self.right None # 右子树 self.is_leaf False # 是否叶子节点 self.leaf_model None # 叶子上的对率回归模型参数逻辑说明内部节点只关心split_feature和split_threshold以及左右子树引用。叶子节点不参与切分但携带leaf_model。这里的leaf_model设计成一个字典而不是一个独立类省去多余的模板代码leaf_model { coef: None, # 逻辑回归权重 w intercept: None, # 偏置 b scaler: None # 叶子内的 StandardScaler }参数说明coef是维度与特征数相同的一维数组intercept是标量scaler必须单独强调——每个叶子要独立做标准化不能拿全局 scaler 替代。因为树切分不受量纲影响但叶子里的逻辑回归梯度下降对尺度极其敏感这个问题在第 5 章还会展开。这种设计的最大好处是预测时递归走到叶子节点直接取出node.leaf_model就能用不需要额外的映射表维护叶子编号和模型之间的关系从根上避免了索引错位这个经典坑。3.3 递归切分用基尼不纯度决定在哪里下刀树的构建过程是一个递归函数给定当前节点和落入该节点的样本找到最优切分点然后递归切左右子树。分类树的切分准则我用基尼不纯度Gini impurity因为它计算比信息熵快而且两者的切分结果在大多数场景下差别不大。def gini(y): classes np.unique(y) n len(y) if n 0: return 1.0 p np.array([np.sum(y c) / n for c in classes]) return 1.0 - np.sum(p ** 2) def find_best_split(X, y): n_features X.shape[1] best_gain -np.inf best_feature, best_threshold None, None parent_gini gini(y) n len(y) for f in range(n_features): values np.unique(X[:, f]) thresholds (values[:-1] values[1:]) / 2.0 for thr in thresholds: left_mask X[:, f] thr right_mask ~left_mask if left_mask.sum() 0 or right_mask.sum() 0: continue gini_left gini(y[left_mask]) gini_right gini(y[right_mask]) weighted (left_mask.sum() * gini_left right_mask.sum() * gini_right) / n gain parent_gini - weighted if gain best_gain: best_gain gain best_feature f best_threshold thr return best_feature, best_threshold, best_gain逻辑说明find_best_split遍历每个特征、每个候选阈值计算切分前后的基尼下降量选下降最多的一组。阈值取相邻特征值的均值这是 CART 的标准做法。parent_gini是切分前整个节点的纯度切分后按左右子节点样本量加权平均得到子节点纯度两者相减就是这次切分带来的纯度增益。参数说明候选阈值数量等于该特征在节点内不同取值个数减一。特征多、样本量大时这个双重循环会成为性能瓶颈手写实现里可以用np.sort加向量化计算加速但作为教学实现保持清晰比追求速度重要。实际工业落地时直接换 sklearn 的DecisionTreeClassifier做切分即可第 4 章会讲这个组合姿势。3.4 叶子上的对率回归梯度下降拟合局部边界树的递归终止条件有三个当前深度达到max_depth、节点样本数小于min_samples_leaf、或者找不到合法切分点。终止后进入叶子拟合阶段。叶子模型不是多数类投票而是对率回归——这里我用自写的批量梯度下降实现保证「python 实现对率回归决策树」这件事没有黑匣子。def sigmoid(z): z np.clip(z, -500, 500) return 1.0 / (1.0 np.exp(-z)) def fit_logistic(X, y, lr0.1, epochs300, l21e-3): if len(np.unique(y)) 2: return None scaler StandardScaler() Xs scaler.fit_transform(X) n, d Xs.shape w np.zeros(d) b 0.0 for _ in range(epochs): z Xs w b p sigmoid(z) grad_w (Xs.T (p - y)) / n l2 * w grad_b np.sum(p - y) / n w - lr * grad_w b - lr * grad_b return {coef: w, intercept: b, scaler: scaler}逻辑说明这个函数就是叶子模型训练的完整流程。先做标准化再初始化 w 和 b 为零向量和零标量。每次迭代算一次全量梯度p - y是逻辑回归损失函数交叉熵对线性输出的导数Xs.T (p - y)是 w 的梯度l2 * w是 L2 正则项的梯度贡献。然后用梯度下降更新参数。参数说明lr0.1是学习率对标准化后的数据来说这个量级足够epochs300是迭代轮数二维特征下收敛很快300 轮足够l21e-3是正则化强度防止叶子样本少时 w 分量过大。这几个参数不是拍脑袋定的——叶子样本量通常在几十到几百之间学习率太大直接震荡太小则收敛慢0.1 配 300 轮是实践经验。如果换了数据集先打印一次 loss 曲线再调。注意一个细节函数开头检查了len(np.unique(y)) 2如果叶子里的样本全是同一类直接返回None。这种情况在树切得很深时非常常见第 5 章会专门讲它的影响。3.5 预测一条样本从根节点走到叶子再走局部模型训练完成后预测过程非常像路由从根节点出发根据每个内部节点的切分特征和阈值决定走左子树还是右子树到达叶子后把样本交给叶子里的对率回归模型输出概率。def predict_proba_tree(node, x): if node.is_leaf: if node.leaf_model is None: return np.array([1.0, 0.0]) if node.majority 0 else np.array([0.0, 1.0]) xs node.leaf_model[scaler].transform(x.reshape(1, -1)) z xs node.leaf_model[coef] node.leaf_model[intercept] p1 sigmoid(z)[0] return np.array([1 - p1, p1]) if x[node.split_feature] node.split_threshold: return predict_proba_tree(node.left, x) else: return predict_proba_tree(node.right, x)逻辑说明这段代码体现了整个模型的核心推理路径。叶子节点里先检查leaf_model是否为None是的话说明该叶子只有一类样本逻辑回归没有学到任何东西这时退化为多数类概率输出——这种做法比强行让逻辑回归拟合单类数据更稳妥。模型存在时必须用叶子内保存的scaler先做同样的标准化再走线性计算最后过 sigmoid。这提醒我们标准化参数必须和模型绑定在同一个叶子节点上训练和预测阶段不能各存各的。到这里一棵完整的对率回归决策树就跑通了。构建时递归切分叶子内梯度下降拟合局部边界预测时硬路由加局部软输出。这就是「决策树如何逼近真实曲线」的最终答案外部是矩形分区给全局形状内部是线性模型给局部精度组合起来形成分段光滑的逼近。4. 用 sklearn 快速落地同一模型apply 方法把叶子变成局部逻辑回归4.1 为什么不能用from sklearn import一个现成模型先把丑话说在前面sklearn 里没有「对率回归决策树」这个类。你翻遍tree模块和linear_model模块都不存在一个把逻辑回归直接塞进叶子节点的现成模型。常见做法是自己组合用DecisionTreeClassifier做分区路由用LogisticRegression做叶子局部模型。这个组合之所以成立是因为 sklearn 的决策树暴露了一个apply方法输入样本返回每个样本最终落到的叶子节点编号。有了这个编号就能把训练集切分成「每个叶子对应的样本子集」然后对每个子集独立训练一个逻辑回归。这是实现本标题最常见、最可靠的从业方案代码量比手写少一个数量级还自带 CART 的实现优化。import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler tree DecisionTreeClassifier( max_depth4, min_samples_leaf40, random_state42 ) tree.fit(X_train, y_train) leaf_ids_train tree.apply(X_train) leaf_models {} for leaf_id in np.unique(leaf_ids_train): mask leaf_ids_train leaf_id X_leaf, y_leaf X_train[mask], y_train[mask] if len(np.unique(y_leaf)) 2: leaf_models[leaf_id] None continue scaler StandardScaler() X_leaf_s scaler.fit_transform(X_leaf) clf LogisticRegression(C1.0, max_iter500) clf.fit(X_leaf_s, y_leaf) leaf_models[leaf_id] (scaler, clf)逻辑说明先训练一棵普通的 CART 分类树apply拿到每个训练样本的叶子编号按编号聚类后对每个叶子独立训练逻辑回归。单类叶子设为None预测时走多数类兜底。这里LogisticRegression之所以能直接用是因为它内置了 liblinear 或 lbfgs 求解器比手写梯度下降更稳尤其在叶子样本量很小时不会出现收敛问题。参数说明max_depth4是新手最容易忽略的参数。手写实现里深一点没关系因为叶子内的逻辑回归能兜底sklearn 组合里树太深会导致叶子样本太少逻辑回归在几十个样本上很容易过拟合。min_samples_leaf40直接保证每个叶子至少有 40 个样本双类样本都有足够的统计量。C1.0是逻辑回归正则化强度的倒数数据标准化后这个值不需要大改。预测时同样先走apply拿叶子编号再查字典取对应模型def predict_proba_sklearn(x_single): leaf_id tree.apply(x_single.reshape(1, -1))[0] model leaf_models.get(leaf_id) if model is None: return np.array([1.0, 0.0]) scaler, clf model x_s scaler.transform(x_single.reshape(1, -1)) return clf.predict_proba(x_s)[0]逻辑说明预测路径与手写版完全一致——树负责路由到叶子叶子内的模型负责输出概率。leaf_models.get(leaf_id)中的.get而不是[]是为了避免测试集被树分到一个训练时没见过的叶子编号时抛 KeyError。虽然 sklearn 的树结构固定后叶子编号集合确定但防御性编程能省掉一次调试时间。4.2 不均衡叶子和 Pipeline 的坑这个组合方案在实践中有一个容易翻车的细节叶子样本不均衡。DecisionTreeClassifier的切分目标是纯度不关心每个叶子最后分到多少样本。所以会出现一个叶子有 500 个样本、另一个叶子只有 40 个的情况。样本量大的叶子逻辑回归学得很稳样本量小的叶子则容易过拟合。应对手段首先是调min_samples_leaf。这个参数同时影响树结构和叶子样本量调大它不仅能避免单类叶子还能间接控制叶子模型的过拟合。其次是逻辑回归的正则化强度叶子样本越少C值应该越小正则化更强。一个比较实用的经验是min_samples_leaf设为总训练样本数的 5%~10%C保持在 0.5~1.0 之间。另一个坑是 Pipeline。很多人习惯用make_pipeline(StandardScaler(), LogisticRegression())一套流程走到底但在这个场景里 Pipeline 反而碍事——你不能把整棵树的apply放进 Pipeline因为每个叶子需要独立的 scaler如果只对全局做一次标准化又违背了「每个叶子独立建模」的初衷。正确做法就是上面代码展示的手动循环叶子手动维护leaf_models字典。为了让这套代码具有复用性我一般把它封装成一个类fit方法里训练树和叶子模型predict_proba方法里做路由和查询外部调用方式与 sklearn 的BaseEstimator保持一致。这样无论是交作业还是做实验都当成一个黑盒模型用后续换数据只需要改参数。5. 对率回归决策树的五个常见坑从叶子样本量到收敛诊断5.1 叶子只有一个类别逻辑回归直接训不出来现象训练时某个叶子内所有样本的 y 标签全是 0 或全是 1。代码跑起来不报错但逻辑回归的权重全为零predict_proba输出的概率恒为 0.5 或者变成极端值测试集准确率反而比普通决策树还低。原因逻辑回归在单类样本上没有可学习的判别信息——正负样本都不齐梯度指向的是「把所有样本推往同一个方向」没有约束力。而决策树在切分时只关心纯度它根本不在乎叶子内部能不能训练出逻辑回归。解决在叶子模型训练前检查类别数量单类叶子直接退化存None预测时用多数类概率兜底。同时把min_samples_leaf调大保证每个叶子至少有 20~30 个样本这是本标题下最容易被忽视、也最容易让新手浪费半天时间的坑。5.2 忘了在叶子内单独做标准化现象同一条数据手写梯度下降实现时 loss 下降极慢甚至震荡换成 sklearn 的LogisticRegression后每次训练都会弹出收敛警告。打印出每个叶子的coef看各维度的权重尺度能差出几个数量级。原因逻辑回归对特征尺度极其敏感。树切分时用的阈值比较不受量纲影响所以整棵树的构建完全正常问题全部集中在叶子内部的线性模型上。如果某个特征的数值范围是另一个特征的 1000 倍梯度下降的更新方向会被大尺度特征主导小尺度特征几乎学不到任何东西。解决每个叶子独立fit_transform一个StandardScaler并把 scaler 实例存在叶子模型里。预测时用同一个 scaler 对样本做变换。这个坑在二维玩具数据上不明显——两个特征量纲接近——但只要换到真实业务数据比如收入预测这种同时含年龄和年薪的任务当场就会暴露。5.3 sklearn 组合实现时叶子索引错位现象预测阶段leaf_models[leaf_id]抛 KeyError或者模型明明训练完了预测结果全乱套。原因典型的错误姿势是训练时换了一个新的树实例或者用tree.apply(X_train)获得的叶子编号去另一个树模型上做预测。sklearn 的apply返回的是节点的唯一编号不同树实例之间编号没有对应关系同理如果你在训练后又重新fit了树之前存的叶子模型就全部作废了。还有更隐蔽的版本树预测时传入了二维数组但没 reshape导致apply返回的形状和你预期不一致。解决训练阶段和预测阶段必须使用同一个树实例。封装成类之后把tree作为实例属性保存不要在任何地方重新赋值或重新训练。如果你拿这段代码去改造成交叉验证记住cross_val_predict这类工具会重新拟合模型叶子模型必须跟着一起重训。5.4 「对率回归决策树」被误用成回归模型现象有人拿着这个模型去预测房价、温度这类连续数值发现输出全是 0 到 1 之间的概率简直没法看。原因标题里「对率回归」中的「回归」是 Logistic Regression 里的回归指的是对「对数几率」这种连续量建模不是「预测连续数值」的回归问题。搜索引擎里搜「回归」进来的人特别多这是最频率最高的误解没有之一。解决明确这个模型是一个分类器输出的是类别概率。如果你要做连续值预测目标模型应该是回归树、GBDT 或随机森林回归器不是这个组合。写代码前先确认任务类型y 标签是离散类别还是连续数值。5.5 只看 loss 下降就以为模型收敛了现象训练循环里打印出 loss 曲线看起来一路向下很漂亮但测试集准确率很差或者 sklearn 的LogisticRegression在训练时直接输出ConvergenceWarning你嫌它吵把warnings关掉了。原因loss 下降只代表目标函数在优化不代表模型泛化好。常见情况是学习率太大导致 loss 在早期快速下降后过冲进入震荡也可能是叶子样本量太少逻辑回归把局部噪声当成正常模式学进去了。关掉 warning 更是在自欺欺人。解决训练时同时打印梯度的范数np.linalg.norm(grad_w)和 loss 值如果 loss 在下降但梯度范数没有收敛到接近零说明学习率偏大或 epoch 不够。换到 sklearn 方案后不要屏蔽 warningmax_iter调大或改用 lbfgs 求解器往往能直接解决。血泪经验是模型不收敛时先看参数诊断不要第一时间怀疑数据有问题。6. 验证分段线性真的学到手决策面可视化与参数诊断理论讲完了代码写完了最后一步是验证这个模型真的学到了「分段线性」而不是退化成普通决策树。最有效的手段是画决策边界对比图。这里给出一个最小可用的可视化代码把普通 CART 树和对率回归决策树画在同一张画布上。import matplotlib.pyplot as plt def plot_decision_boundary(model, X, y, ax, title, predict_fn): x_min, x_max X[:, 0].min() - 0.3, X[:, 0].max() 0.3 y_min, y_max X[:, 1].min() - 0.3, X[:, 1].max() 0.3 xx, yy np.meshgrid( np.linspace(x_min, x_max, 300), np.linspace(y_min, y_max, 300) ) grid np.c_[xx.ravel(), yy.ravel()] z np.array([predict_fn(model, x) for x in grid]) z z.reshape(xx.shape) ax.contourf(xx, yy, z, alpha0.6, levels20, cmapcoolwarm) ax.scatter(X[:, 0], X[:, 1], cy, edgecolork, s20) ax.set_title(title)逻辑说明在二维平面上生成密集网格点对每个网格点调用模型的预测函数把预测概率或类别填充成背景色。普通决策树的背景会出现明显的矩形色块边界是直角阶梯对率回归决策树的背景则是被矩形划分的多个渐变区域每个区域内颜色平滑过渡区域边界处才会出现方向变化——这就是分段线性逼近的真实样貌。验证函数写好后用同一个测试集分别调用普通 CART 和组合模型的边界图你会直观看到普通决策树的决策边界像马赛克对率回归决策树则是「每块砖内部有颜色渐变」。另外还要养成一个习惯训练结束后打印几个叶子的leaf_model[coef]对比不同区域权重向量的大小和方向。如果两个相邻叶子的 w 方向差异极大说明这个区域的边界确实在改变而非全图共用一条直线。我自己的教训是早期跑这个模型只看准确率觉得比 CART 高两三个点就完事了直到有一次把决策边界画出来才发现某个叶子的逻辑回归权重被某个特征完全主导形状非常奇怪——根因就是没在叶子内做标准化。从那以后我跑任何混合模型都坚持「先画边界、再打印参数、最后才看指标」的顺序。这个习惯帮我避免了很多自我感觉良好的翻车时刻。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑