4、决策树的可解释性:决策树的可视化与规则提取,特征分裂点与信息增益,决策路径的局部解释

说到模型可解释性,我第一个想到的就是决策树。为什么?因为它是唯一一个「自己长什么样,解释起来就什么样」的模型。你想想看,神经网络像个黑盒子,SVM 的核函数映射到高维空间后根本没法看,但决策树不一样——它本身就是一堆 if-else 规则的集合。

我个人习惯在做评分卡或者风控模型时,先用决策树打个底。不是为了追求精度,而是为了快速理解数据里的结构。说白了,决策树的可解释性,就是它最大的武器。

4.1 决策树的可视化:让模型「长」出来

先聊聊可视化。我见过不少团队,模型跑完了,但业务方问「为什么这个人被拒了?」——答不上来。决策树就不一样,你可以直接把树画出来给他们看。

在 Python 里,最常用的就是 sklearn.tree.plot_tree。我贴一段我常用的代码:

from sklearn.tree import DecisionTreeClassifier, plot_tree
import matplotlib.pyplot as plt

# 训练一个简单的决策树
clf = DecisionTreeClassifier(max_depth=3, random_state=42)
clf.fit(X_train, y_train)

# 可视化
plt.figure(figsize=(20, 10))
plot_tree(clf, 
          feature_names=['年龄', '收入', '负债率', '信用历史'],
          class_names=['好客户', '坏客户'],
          filled=True,
          rounded=True,
          fontsize=12)
plt.show()

这里有个小细节:filled=True 会让每个节点根据类别着色,颜色越深代表纯度越高。我在做信贷评分项目时,业务方一看这图就懂了——「哦,原来收入低于 5 万且负债率高于 40% 的人,基本都被拒了」。这就是可视化的力量。

我的经验: 树太深了就别画了,超过 5 层基本就是一团乱麻。我一般限制 max_depth=3 或 4,既能解释清楚,又不会吓到业务方。

4.2 规则提取:把树变成「如果...那么...」

可视化是给人看的,但有时候我们需要把规则提取出来,写到文档里或者嵌入到业务系统中。这时候就要做规则提取。

决策树的本质是什么?就是从根节点到每个叶子节点的一条路径。每条路径就是一条规则。我常用的方法是递归遍历树结构:

from sklearn.tree import _tree

def tree_to_rules(tree, feature_names):
    tree_ = tree.tree_
    feature_name = [
        feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!"
        for i in tree_.feature
    ]
    
    def recurse(node, depth, rule):
        if tree_.feature[node] != _tree.TREE_UNDEFINED:
            name = feature_name[node]
            threshold = tree_.threshold[node]
            
            # 左分支:小于等于阈值
            left_rule = rule + [f"{name} <= {threshold:.2f}"]
            recurse(tree_.children_left[node], depth + 1, left_rule)
            
            # 右分支:大于阈值
            right_rule = rule + [f"{name} > {threshold:.2f}"]
            recurse(tree_.children_right[node], depth + 1, right_rule)
        else:
            # 叶子节点,输出规则
            value = tree_.value[node]
            class_pred = value.argmax()
            print("IF " + " AND ".join(rule) + f" THEN 类别={class_pred}")
    
    recurse(0, 0, [])

运行这段代码,你会得到类似这样的输出:

IF 年龄 <= 35.00 AND 收入 <= 8.50 THEN 类别=0
IF 年龄 <= 35.00 AND 收入 > 8.50 THEN 类别=1
IF 年龄 > 35.00 AND 负债率 <= 0.40 THEN 类别=1
IF 年龄 > 35.00 AND 负债率 > 0.40 THEN 类别=0

嗯,这里要注意:规则的数量等于叶子节点的数量。如果树很深,规则会爆炸式增长。我曾经在一个项目里,树深度设到 10,结果提取出 500 多条规则——这哪叫可解释性?这叫灾难。所以我的建议是:规则数量控制在 10 条以内,超过这个数,你就该考虑剪枝或者换模型了。

4.3 特征分裂点与信息增益:树是怎么「做决定」的

决策树每次分裂,都要选一个特征和一个阈值。选谁?标准就是信息增益。

信息增益的公式其实不复杂:

信息增益 = 父节点的熵 - 子节点的加权熵

说白了,就是看分裂之后,数据「乱不乱」的程度降低了多少。降低得越多,这个分裂就越好。

我举个例子。假设我们有 100 个样本,50 个好客户,50 个坏客户。父节点的熵就是:

熵 = - (0.5 * log2(0.5) + 0.5 * log2(0.5)) = 1.0

现在按「收入是否大于 10 万」分裂:

  • 左子节点(收入 ≤ 10 万):60 个样本,40 好 20 坏,熵 = 0.918
  • 右子节点(收入 > 10 万):40 个样本,10 好 30 坏,熵 = 0.811

加权子节点熵 = (60/100)*0.918 + (40/100)*0.811 = 0.875

信息增益 = 1.0 - 0.875 = 0.125

如果换成按「年龄是否大于 30」分裂,信息增益只有 0.05,那算法就会选「收入」作为分裂特征。

关键点: 信息增益越大,说明这个特征对区分目标变量越有用。在评分模型里,信息增益高的特征往往就是业务上的「强变量」。

我在做信用卡评分模型时,发现「近 6 个月逾期次数」的信息增益远高于「年龄」。这其实符合业务直觉——还款行为比人口属性更能预测违约风险。

4.4 决策路径的局部解释:为什么这个人被拒了?

全局解释看的是整棵树,局部解释看的是单个样本。比如一个客户被拒了,他问「为什么?」——你不能说「因为模型觉得你风险高」,得给出具体理由。

决策树的局部解释很简单:从根节点开始,沿着分裂条件一路走到叶子节点,记录下所有经过的节点条件。这就是该样本的决策路径。

我写了个小函数来做这件事:

def explain_sample(tree, feature_names, sample):
    tree_ = tree.tree_
    node = 0
    path = []
    
    while tree_.feature[node] != _tree.TREE_UNDEFINED:
        feat = feature_names[tree_.feature[node]]
        thresh = tree_.threshold[node]
        
        if sample[tree_.feature[node]] <= thresh:
            path.append(f"{feat} <= {thresh:.2f}")
            node = tree_.children_left[node]
        else:
            path.append(f"{feat} > {thresh:.2f}")
            node = tree_.children_right[node]
    
    value = tree_.value[node]
    pred_class = value.argmax()
    prob = value[0][pred_class] / value.sum()
    
    return {
        'path': ' → '.join(path),
        'predicted_class': pred_class,
        'probability': prob
    }

# 使用示例
sample = X_test[0]
result = explain_sample(clf, ['年龄', '收入', '负债率', '信用历史'], sample)
print(result['path'])
# 输出: 收入 <= 8.50 → 负债率 <= 0.30 → 信用历史 > 2.00 → 类别=1

你看,这个路径就是给业务方看的解释:「因为你的收入低于 8.5 万,负债率低于 30%,但信用历史超过 2 年,所以被判定为好客户」。每一条都对应一个具体的业务含义。

避坑指南: 我曾经遇到过一个问题——决策树的局部解释路径虽然清晰,但如果树很深,路径会很长,业务方根本记不住。我的做法是:只展示前 3 个分裂条件,后面的用「以及其他条件」概括。解释性不是越详细越好,而是越「可理解」越好。

4.5 知识体系总览

为了让你更直观地理解本章的知识结构,我画了一张图:

决策树可解释性知识体系 决策树可解释性 可视化 plot_tree / Graphviz 规则提取 IF-THEN 规则 / 递归遍历 特征分裂与信息增益 熵 / 基尼系数 / 分裂点 决策路径局部解释 单样本路径 / 业务解释 树结构图 节点纯度着色 规则数量控制 熵的计算 分裂点选择 路径追踪 业务化解释 核心目标:让业务方看懂、用上、信任模型

这张图把本章的四个核心内容串起来了。你可以看到,可视化、规则提取、信息增益、决策路径,它们不是孤立的,而是从不同角度回答同一个问题:模型为什么这么判断?

好了,这一章就聊到这儿。决策树的可解释性,说白了就是「把模型翻译成人话」。你掌握了可视化、规则提取、信息增益和局部路径这四招,基本上就能应对 90% 的业务解释需求了。下一章我们聊聊线性模型的可解释性——那个更简单,但也更容易踩坑。


专注资料整理