财务舞弊检测实践 · 第 10

SHAP 可解释性与方法选择决策树

第 9 章在文本特征上做完了"演示性"实验,把财务数字之外的模态接到了同一个预测框架里。到现在,本书的十种方法已经全部登场过一次。从第 2 章 Beneish 的八变量规则,到第 5 章随机森林把 AUC 推上 0.71,再到第 6 章 XGBoost 意外地跌回 0.65,每一种方法都给同一份 Bao 数据交了一份成绩单。这一章不再新增预测方法,把任务收回到三件事上:让最佳模型说出它"为什么这么打分",把十种方法摊在一张终极对比表上,再给读者一份按场景分支的方法选择清单。

审计师在实际工作中拿到一个机器学习模型的舞弊概率打分时,第一句问话总是"为什么是这家公司"。如果模型只能给出一个 0.98 的数字,没有任何关于这个数字怎么来的解释,审计师没办法把它写进工作底稿里向合伙人交代。监管者面对同样的问题。SEC 在分配执法资源时不能只靠一个排序,必须给国会和上诉法庭一份"基于哪些事实做出怀疑判断"的清单。学术研究者面对的是另一种压力。一篇审稿人会问"你的随机森林为什么把 soft_assets 排第一,背后的会计故事是什么",给不出回答论文就过不了同行评审。三类读者的诉求不一样,但都要求同一件事,模型的预测必须能拆开看。

Shapley 值的合作博弈论基础

停下来想一想。 假设你手里有 42 个会计变量,模型对一家公司预测出舞弊概率 0.98。怎么把这 0.98 公平地分摊到 42 个变量上?最直观的做法是"逐个去掉一个变量看预测下降多少",但这种朴素方法漏掉了变量之间的交互。soft_assets 单独存在时贡献 0.20,去掉它预测降到 0.78;可如果同时去掉 sstk,预测可能跌到 0.40,意味着两个变量联合时还有额外贡献。

合作博弈论里这套问题在 1953 年被 Shapley 解决过。设想一群玩家共同生产一笔总收益,怎么把这笔收益公平分给每个人?Shapley 给出的方案是看每个玩家在所有可能的"加入顺序"下的边际贡献,再做一个均匀加权平均。这个方案的好处在它满足四条公理,对称性、虚拟性、加性、效率,对应到预测可解释性场景就是"两个等同变量分配相等贡献""完全不影响预测的变量贡献为零""贡献可加""所有贡献之和等于实际预测减去基线"。Lundberg 与 Lee 在 2017 年把这个想法套到机器学习模型预测上,提出 SHAP,然后在 2020 年给出对树模型的高效精确算法。

定义SHAP 值

ff 是模型在特征 x=(x1,,xp)x = (x_1, \ldots, x_p) 上的输出,ϕ0\phi_0 是基线期望预测 E[f(x)]\mathbb{E}[f(x)]。第 jj 个特征对该样本预测的 SHAP 值定义为

ϕj(x)=S{1,,p}{j}S!(pS1)!p![fS{j}(x)fS(x)],\phi_j(x) = \sum_{S \subseteq \{1,\ldots,p\}\setminus\{j\}} \frac{|S|!\,(p - |S| - 1)!}{p!} \bigl[ f_{S \cup \{j\}}(x) - f_S(x) \bigr],

其中 SS 是不含 jj 的特征子集,fS(x)f_S(x) 是只用 SS 中特征时的条件期望预测。SHAP 值满足 f(x)=ϕ0+j=1pϕj(x)f(x) = \phi_0 + \sum_{j=1}^p \phi_j(x)

举一个数字例子。Bao 数据里 chap06 训练好的 XGBoost 给出基线 logit ϕ0=0.948\phi_0 = 0.948。Enron 2000 这家公司预测 logit 是 4.115。这两个数差 3.167,正是 42 个特征的 SHAP 值之和。其中 csho 这个变量贡献 +0.97,act 贡献 +0.58,sstk 贡献 +0.48,pstk 贡献 −0.43,soft_assets 贡献 +0.36,前 5 个特征加起来已经 +1.97,占总抬升的六成。剩下 37 个特征零零散散合计贡献 +1.20,把 logit 从基线推到 4.115。最后 logit 经 sigmoid 映射成概率 0.984。

直接按定义计算需要遍历 2p2^p 个子集,对 42 个特征意味着 4.4 万亿次评估,完全跑不动。Lundberg 等人 2020 年的 Tree SHAP 算法把树模型上的精确 SHAP 值算到 O(TLD2)O(TLD^2) 时间,其中 TT 是树数、LL 是叶子数、DD 是树深。本章测试集 27,628 行 × 42 个特征的 SHAP 数组在本机几秒钟就跑完。

全局 SHAP:变量重要性的稳健替代

第 5 章给过两份变量重要性榜单,MDI 与 MDA。两者机制不同,结论的差异让"哪个变量最重要"这个问题没有干净答案。SHAP 在这里给出第三条路径,把所有样本的局部 SHAP 值取绝对值再平均,得到 mean(|SHAP|)。这个量比 MDI 稳定,比 MDA 便宜,且能直接和单条预测对应起来。

定义全局 SHAP 重要性

对样本集合 {xi}i=1n\{x_i\}_{i=1}^n 与第 jj 个特征,定义

Ij=1ni=1nϕj(xi).I_j = \frac{1}{n} \sum_{i=1}^{n} \bigl| \phi_j(x_i) \bigr|.

IjI_j 衡量的是 xjx_j 在所有样本上的平均贡献幅度。值越大,该特征对模型预测的整体影响越大。

Bao 测试集 27,628 行的全局 SHAP Top-10 列在下表。

表 10·1 XGBoost 全局 SHAP 重要性 Top-10,测试集 n=27,628

排名特征mean(|SHAP|)
1soft_assets0.5822
2sstk0.4447
3reoa0.3371
4act0.2329
5prcc_f0.2249
6ppegt0.2088
7bm0.1896
8che0.1563
9csho0.1529
10re0.1525

第一名 soft_assets 与第 4 章 LASSO 系数榜单的第一名一致,会计学解读也一致:软性资产占总资产的比重越高,公司账面操纵的空间越大。第二名 sstk 即股票回购,新进入榜单,提示模型注意到了"在外部融资压力下做账"与"在大量回购股票时做账"两类不同的信号。第三名 reoa 是留存收益比资产,第六名 ppegt 是固定资产,第七名 bm 是账面市值比,这一组反映公司的资本结构与估值水平。

把这份 SHAP 榜单与第 5 章 RF 的 MDI / MDA 榜单并排看,能看出三件事。第一,SHAP 榜单的头部稳定,soft_assets 在 SHAP 与 LASSO 上都登顶,与 sstk 一同把账面操纵空间与融资活动顶到最前。第二,MDI 把 soft_assets 排第一是合理的,但它把 prcc_fcsho 这种连续型变量排到前三,被 Strobl 等人警告过的"偏向连续变量"问题在 SHAP 排序里得到部分修正。第三,MDA 把 lctat 这些规模科目排前列,与 SHAP 的差距说明两者诊断的不是同一件事:MDA 看"扰动后预测精度怎么变",SHAP 看"特征对单条预测的贡献",前者偏向被打乱后总体性能波动大的变量,后者偏向单条预测里推力大的变量。

回到 AAER 数据。 站在审计师的角度,SHAP 榜单给出的索引比 MDI 更直接。soft_assets 排第一意味着审计资源应优先核查应收账款、商誉、存货这一组软性资产;sstk 排第二意味着对正在回购股票的公司也要保持警惕。这种"看特征排榜单 → 决定查哪几张表的哪几行"的工作流,是 SHAP 对会计实务最直接的接口。

局部 SHAP:逐家公司的逐变量分解

全局 SHAP 给出的是"模型整体上看哪些特征重要",没法回答"为什么模型把这家公司打到 0.98"。局部 SHAP 才是审计师最需要的工具。每一行测试样本都对应一份 42 维的 SHAP 向量,把它从大到小排,看哪几个特征把这家公司从基线推上去、哪几个把它拉下来,故事就拼出来了。

雷区SHAP 不是因果效应

SHAP 给出的是"特征对模型预测"的归因分解,不是"特征对结果"的因果效应。Enron 2000 的 csho SHAP 值 +0.97 只意味着这家公司的发行股数取值让模型上调了 0.97 个 logit 单位的舞弊预测,并不意味着发行股数本身导致了舞弊。两个高度相关的特征 actat 在 SHAP 框架下会被 Shapley 公平性公理"对称地"拆分贡献,但模型实际只挑了一个做分裂,另一个的 SHAP 值反映的是"如果它单独存在会贡献多少"。把 SHAP 值当作政策干预的预期效果或会计准则更改的预期影响是危险的,正确的因果问题需要另一套工具。

把 chap06 训练好的 XGBoost 拿到 Enron 2000 与 Tyco 2000 这两条记录上做 SHAP 分解,得到下表。

表 10·2 Enron 2000 与 Tyco 2000 的局部 SHAP Top-5 贡献

案例pred logitpred prob贡献排序特征:SHAP
Enron 2000+4.11450.98391csho: +0.9713+0.9713
2act: +0.5816+0.5816
3sstk: +0.4846+0.4846
4pstk: 0.4289-0.4289
5soft_assets: +0.3575+0.3575
Tyco 2000+2.06240.88721csho: +0.7358+0.7358
2sstk: +0.6253+0.6253
3EBIT: 0.4785-0.4785
4act: +0.4465+0.4465
5soft_assets: +0.4147+0.4147

读 Enron 2000 这一行。基线 logit 0.948 加上前 5 个特征贡献 +1.97 已经把预测推到了 2.92,剩下 37 个特征再贡献 +1.20,最终 logit 落到 4.115,sigmoid 映射后概率 0.984。审计师如果想用一句话向合伙人解释为什么模型把这家公司排到测试集前 1%,可以这样讲:第一是发行股数 csho 处于行业极端高位,2000 年 Enron 在外流通普通股的标准化值远高于训练样本均值;第二是流动资产 act 偏高,第三是股票回购量 sstk 偏高;这三件事在数据里同时出现,模型把它们拼合起来推断为"急速扩张同时回购"的可疑模式。pstk 即优先股的取值反向贡献 −0.43,是模型唯一的"减分项",说明 Enron 在优先股科目上的取值反而看起来不可疑。

图 10·1 SHAP 瀑布分解 Enron 2000 的预测 logit。从基线 ϕ0=0.948\phi_0 = 0.948 出发,前 5 个最有贡献的特征(csho 等)把 logit 累加推到 2.91,剩余 37 个特征再贡献 +1.20,最终落到 4.115,sigmoid 后概率 0.984。完整 TikZ 结构图详见 PDF 全文。

Tyco 2000 的 logit 推到 2.062,概率 0.887,比 Enron 略低。看 SHAP 排序,cshosstkactsoft_assets 这四个核心特征仍然排在前列,但贡献幅度不及 Enron 那么集中。EBIT 在 Tyco 上排第三且方向为负,意味着 Tyco 的息税前利润看起来"略微"挡住了一部分舞弊嫌疑。这与第 4 章 LASSO 给两家公司的差距方向一致:LASSO 把 Enron 推到 0.73,把 Tyco 只推到 0.09,Enron 在多个特征上同时极端,Tyco 仅在部分特征上偏离。

在 Bao 数据上的 SHAP 实验

把所有事情拼起来,对应的 Python 脚本是 code/10_shap.py。它直接加载 chap06 已经保存的 06_xgboost_best.json 模型与 StandardScaler,避免 chap10 内部重训。对测试集 27,628 行调用 shap.TreeExplainer,几秒内拿到 27,628×4227{,}628 \times 42 的 SHAP 数组。

import xgboost as xgb, shap, pickle
from sklearn.preprocessing import StandardScaler
import numpy as np, pandas as pd

np.random.seed(2026)
booster = xgb.Booster()
booster.load_model("code/_models/06_xgboost_best.json")

scaler = StandardScaler().fit(X_train_raw)
X_test = scaler.transform(X_test_raw).astype(np.float32)

explainer   = shap.TreeExplainer(booster)
shap_values = explainer.shap_values(X_test)        # (n, 42)

mean_abs = np.mean(np.abs(shap_values), axis=0)
top10 = (pd.Series(mean_abs, index=features)
           .sort_values(ascending=False).head(10))
print(top10.round(4))
结果解读SHAP 实验输出

脚本读 chap06 已有 booster,不再重训。测试集 AUC 复核 0.6480,与 code/_models/06_xgboost_meta.json 完全一致。基线 logit E[f(x)]=0.948\mathbb{E}[f(x)] = 0.948。全局 mean(|SHAP|) Top-10 把 soft_assetssstk 推到前两位。把 Enron 2000 与 Tyco 2000 单独 transform 后传 explainer.shap_values,得到上节局部分解表。完整 SHAP 数组与全局 / 局部 csv / json 落在 code/_shap_artifacts/ 下,供后续画图复用。

时间外推塌陷

第 1 章在切分协议表里留过一个伏笔。训练期 1991–2002 舞弊率 0.787%,验证期 0.742%,到测试期 2009–2014 跌到 0.339%。第 6 章把这件事第一次量化为模型表现的下挫。同一份 chap06 XGBoost 在验证集上 AUC = 0.7541,到了测试集 AUC 跌到 0.6480,下跌 0.106。原因不能归结到模型过拟合训练集,因为最优轮数是用验证集 AUC 早停选出来的,模型在验证集上已经见过 0.7541 的真实表现。真正的成因是测试集上的标签分布与训练 / 验证期不同了。

测试期舞弊率仅 0.339% 包含两层原因。第一层是 SEC 执法的时滞:2014 年做的舞弊在数据集冻结的时刻可能仍在调查中,AAER 公告未发出,标签为 0;2026 年再回头看,这部分标签会陆续填上。第二层是 SOX 法案 2002 年签署之后,公司治理与内部审计要求大幅加严,激进做账的"性价比"显著下降。两层原因叠加,让 2009–2014 年的样本里"看起来像舞弊但被打成 0"的比例上升。模型在训练期学到的舞弊特征模式,到测试期的新样本上仍然会被识别为可疑,但其中相当一部分是"未来会被 AAER 标记但目前标签是 0"或"在新治理环境下不够程度被起诉"。AUC 这个排序指标对标签缺失非常敏感,下挫几乎是数学必然。

这个现象在英文文献里叫 concept drift 或 label drift。Bao 等人 2020 年的原文也观察到类似下挫,他们用滚动窗口与重训缓解。本书不展开缓解技术,提醒读者一件事:任何在 1991–2008 数据上训练的舞弊检测模型,部署到 2020 年代的实务数据时,不应该期待训练期的 AUC 数字。合理的做法是定期用最近三到五年的新 AAER 公告重训模型,并在每次重训时重新审视特征工程。

十种方法的终极对比

把前九章的测试集数字和本章的 SHAP 增量并排放到一张表上,得到本书最终的累积对比表。表里每一行都是真实从代码跑出来的数字,与 _NUMBERS.md 里的章节段落一一对应。

表 10·3 十种方法终极对比表,测试期 2009–2014

方法AUCNDCG@100Recall@1%Precision@1%训练时间核心局限
零模型 ch10.5000.00000.00000.00000 s无判别力
Beneish M-Score ch20.53990.00000.01100.0049< 1 s八规则固定,不学习
逻辑回归 42 特征 ch30.69660.05100.05610.0217数秒高维下系数不稳
LASSO 最优 ch40.68760.04950.05610.0217数秒不平衡下易压零
单棵决策树 ch50.54830.00720.03740.01441 s不稳定,过拟合
随机森林 ranger ch50.70870.01500.03740.014418.7 sMDI 偏向连续变量
XGBoost 调参后 ch60.64800.00860.02800.01081.2 s时间外推塌陷
RUSBoost Bao 复刻 ch70.69820.00950.02680.0091数秒欠采样信息丢失
MLP ch80.59440.00000.01870.00721.06 s表格上弱于树类
Isolation Forest 无监督 ch80.57150.04810.03740.01440.52 s与 AAER 标签弱关联
XGBoost + SHAP ch100.64800.00860.02800.01081.2 s + SHAP归因,非因果

读这张表能看出几条规律。第一,传统方法与机器学习方法的差距没有想象中那么悬殊。chap03 的逻辑回归在测试集上 AUC = 0.6966,与 chap05 随机森林的 0.7087 只差 1.2 个百分点;与 chap06 XGBoost 调参后的 0.6480 还要高出 5 个百分点。Bao 2020 的 RUSBoost 在本书复刻下测试 AUC 0.6982,与 chap03 的逻辑回归 0.6966 几乎打平,与 chap05 随机森林 0.7087 只差 1 个百分点。读者应当把这看作对机器学习应用边界的提醒,不是对机器学习价值的否定:在样本量充足、变量集干净、标签噪声以阴性遗漏为主的会计 ML 场景下,方法之间的差距远小于"传统 vs 现代"这个二分法的暗示。

第二,前 1% 排序指标比 AUC 更挑剔。Recall@1% 与 Precision@1% 在 chap03 / chap04 这种线性方法上能拿到 0.056 / 0.022,在 chap05 RF 与 chap06 XGBoost 上反而跌回 0.037 / 0.014。这意味着随机森林与 XGBoost 改进了"中段排序",但前 1% 的命中率受到舞弊基率本身只有 0.34% 的硬约束。任何在审计资源稀缺场景下部署的模型,都需要在 Recall@1% 这个指标上专门诊断。

第三,无监督方法 IsolationForest 给出了一个有趣的反例。它的 AUC 仅 0.572,但 NDCG@100 达到 0.048,远高于 RF 的 0.015。这是无监督异常检测的特性:它不学习舞弊标签,而是在特征空间里找"远离主体"的样本,这些样本里舞弊样本碰巧被排在头部位置的概率比 RF 还高。当审计师手上的 AAER 标签被严重质疑时,无监督方法是值得回头考虑的备选。

方法选择决策树

把上面三条规律拼起来,本书给出一份按场景分支的方法选择清单。决策依据有三个维度:标签可信度、计算资源、可解释性要求。

第一支:标签可信、资源充足、可解释要求高。这是大多数会计学术研究与监管侧分析的场景。推荐 XGBoost + SHAP 的组合。XGBoost 抓住非线性与变量交互,SHAP 给出全局与局部双层解释,能直接对接审计底稿与监管报告的"为什么"问题。如果对前 1% 排序更敏感,可以并行跑随机森林做交叉验证。

第二支:标签可信、资源充足、可解释要求低。比如内部审计的"按风险打分给抽样表"。RUSBoost 是参考论文复刻的旗舰方法,直面类别不平衡,部署成本可控。如果不在乎 0.05 量级的 AUC 差距、追求开箱即用,随机森林也是合理选择。

第三支:标签不可信。当研究者怀疑 AAER 标签的阴性遗漏过于严重,或目标人群与 SEC 执法管辖范围不重叠,例如境外公司或私募市场,有监督方法的训练目标本身就不可信。Isolation Forest 在本章对比表里 AUC 只有 0.572,但它不依赖标签,可以作为"先把异常公司挑出来给人审"的第一道筛子,再让人类专家或后续监管程序介入。

第四支:资源极度受限。比如小型审计所没有数据科学团队、临床手工做盘前筛查。Beneish M-Score 是合理的 first-pass screen,八个变量三十年不变,公开复刻成本接近零。它的 AUC 只有 0.540,但作为"把可疑公司从全样本里捞一遍"的零智能筛子已经够用。

四支决策不必互斥。一个完整的舞弊筛查流水线可以是:M-Score 做粗筛,Isolation Forest 在粗筛后的样本上找异常,最后对异常样本调用 XGBoost + SHAP 给出可解释的精排序与逐变量分解。每一层用最适合的工具,比指望单一方法解决所有问题更稳健。

给三类读者的不同结论

最后一节面向三类不同身份的读者,把全书的结论翻译成各自能直接行动的建议。

审计师 面对的是"如何把模型嵌入到执业流程里"。建议把 XGBoost + SHAP 视为 Beneish M-Score 的现代版补充,而不是替代品。M-Score 因其规则简单仍然有进入工作底稿的合规价值,SHAP 给出的局部分解则是对每一家被模型标记为可疑的公司提供逐变量证据,方便在审计意见里说清楚"为何提请管理层注意"。重点关注 soft_assetssstkact 三个 SHAP 排名前列的科目,这是模型在 Bao 数据上反复抓住的舞弊信号源。

监管者 面对的是"如何在执法资源稀缺下提高命中率"。建议把 Recall@1% 与 Precision@1% 作为模型选型的首要指标,AUC 仅作辅助参考。本书测试集上 1% 名额对应 277 家公司,逻辑回归与 LASSO 在这个名额下能命中 6 家真舞弊,召回率 5.6%,已经显著优于随机抽样的 1% 召回。把这个名额作为执法启动调查的初筛清单,配合 SHAP 给出的逐家公司证据链,能在公开听证或国会质询中给出"为什么这家公司被列为重点"的清晰回答。

学术研究者 面对的是"如何让方法学进展能在同行评审中通过"。建议报告至少四个指标 AUC / NDCG@100 / Recall@1% / Precision@1%,并提供全局 SHAP 与若干典型样本的局部 SHAP 分解。如果是新方法的提案,必须与本书第 3 章逻辑回归这种基线做严格对比;如果是新数据的应用,必须报告时间外推塌陷的验证 vs 测试 AUC 差距。审稿人会反复问的"机器学习相对传统方法到底贡献了多少",靠这些数字与可解释性产出说话。

回到 AAER 数据。 本书第 1 章问过一个问题:能不能在 SEC 处罚之前把可疑公司识别出来。十种方法的回答有一个共同结论。在 2009–2014 测试期样本里,模型可以把舞弊公司排到测试集前 1% 的概率约是基线的 5–16 倍,但仍然只能抓住总舞弊数的一小部分。机器学习不会替代审计师的专业判断,它只是让审计师在有限的执业时间里把注意力放在最可能出问题的公司上。这是本书想留给读者的最实在的一句话。

本章累积对比表 终极版

终极对比表已经在表 10·3 给出,本节不再重复。需要强调的一点是:表中各行的测试集口径并不完全一致。chap02 由于 lag 与变量构造,测试集 n=20,236, k=203, 阳性 91;chap07 RUSBoost 仅用 28 个原始 Compustat 变量,drop NA 后测试集 n=33,064, k=331, 阳性 112;其余方法采用 chap03 起统一的 42 特征 drop NA 协议,测试集 n=27,628, k=277, 阳性 107。比较行间数字时需要意识到这一差异。

本章知识地图

表 10·4 第 10 章核心概念与常见误解

核心概念核心内容常见误解为什么错
Shapley 值合作博弈论里满足对称性、虚拟性、加性、效率四公理的唯一公平分配方案Shapley 值衡量的是变量对结果的因果效应Shapley 值只衡量"特征对模型预测"的归因,不衡量"特征对真实结果"的因果效应
SHAP 值把 Shapley 值套用到模型预测的归因分解,满足 f(x)=ϕ0+jϕj(x)f(x) = \phi_0 + \sum_j \phi_j(x)SHAP 值正等于"该特征让预测变高"SHAP 值是相对基线 E[f(x)]\mathbb{E}[f(x)] 的偏移;单条样本的正负只反映相对位置
Tree SHAP对树模型用动态规划在 O(TLD2)O(TLD^2) 内精确求 SHAP 值,不用蒙特卡洛近似树越深 SHAP 越准Tree SHAP 是精确算法;"深度增加 SHAP 更准"概念不存在
全局 mean(|SHAP|)把每条样本的 |SHAP| 取平均,得到稳健的全局变量重要性与 MDI / MDA 排名应该一致三者机制不同,头部头几个变量重合,尾部排序差异较大
局部 SHAP单条样本的 42 维 SHAP 向量给出该公司被打分的逐变量证据把 Top-5 SHAP 当成"这家公司舞弊的原因"SHAP 值是模型怎么打分的拆解,不是公司为什么舞弊的因果说明
时间外推塌陷训练 / 验证 → 测试期标签分布漂移导致模型 AUC 下挫 0.10 量级AUC 下挫一定是模型过拟合早停由验证集 AUC 选定,模型并未过拟合;下挫主要来自标签缺失与制度变迁
方法选择决策树按"标签可信度 / 资源 / 可解释性要求"三维度分四支XGBoost + SHAP 永远最优标签不可信场景下 IF 更稳健,资源极受限场景下 M-Score 仍是合理首选
四指标联合报告AUC / NDCG@100 / Recall@1% / Precision@1% 一并报AUC 高就说明模型实用审计场景下前 1% 排序受舞弊基率约束,AUC 高不保证 Recall@1% 高