财务舞弊检测实践 · 第 3

F-Score:带学习的逻辑回归

第 2 章用 Beneish 八变量 M-Score 在测试集上跑出 AUC = 0.5399,前 100 名零命中。那个模型把每个公司的 8 个比率打分后线性加权,权重是 Beneish 1999 论文用 1982–1992 年 74 家被 SEC 处罚公司样本拟合出来的常数。常数权重的好处是简洁,坏处也明显:换一份新数据,权重永远不会自动调整。要让权重根据样本"学"出来,就要把规则模型升级为统计模型。这一章引入会计学界用了三十年的工具:逻辑回归。配合 Dechow 等人 2011 年发表在 Contemporary Accounting Research 上的那篇 65 页长论文,我们要复刻 F-Score 的原始设计,看看它在 Bao 复制包上的判别力还剩多少。

逻辑回归在会计 ML 文献里有特殊地位。它既是 1980 年代以来银行违约预测、破产预测、舞弊检测的工作母机,也是 2010 年代以后被树模型与神经网络逐步取代的"经典基线"。把它放在第 3 章,是要让读者亲手感受一件事:在固定特征集和无正则的 MLE 设定下,逻辑回归能给出一个排序得分,比恒预测多数类的零模型好得多,但离机器学习时代的 AUC 上限还隔着相当一段距离。

从规则到概率

第 2 章 M-Score 的输出是一个连续的实数分数,没有概率含义;它落在哪个区间,全靠 Beneish 经验切的阈值 2.22-2.22。逻辑回归不一样,它直接输出"这家公司在这一年被记为舞弊的概率"。要让模型输出概率,需要一个把任意实数压缩到 [0,1][0,1] 区间的函数,这个函数叫 sigmoid 函数,简称 logistic 函数。

举一个数字例子。假设我们用一个简化模型:只用 ch_roa,也就是资产回报率年度变化,作为唯一变量预测舞弊。某家公司的 ch_roa0.05-0.05,模型估计的截距是 7.4-7.4、斜率是 0.42-0.42。把数字代进线性部分得到 7.4+(0.42)×(0.05)=7.379-7.4 + (-0.42) \times (-0.05) = -7.379。这个 7.379-7.379 没有概率含义,它叫 log-odds。把 log-odds 通过 sigmoid 变换:1/(1+e7.379)0.000621/(1 + e^{7.379}) \approx 0.00062,得到这家公司被舞弊的预估概率 0.062%。

定义逻辑回归与 log-odds
def:logit

Y{0,1}Y \in \{0,1\} 是二元结局,x\mathbf{x} 是协变量向量,P=Pr(Y=1x)P = \Pr(Y = 1 \mid \mathbf{x})。逻辑回归假设

logit(P)=logP1P=β0+βx.\mathrm{logit}(P) = \log\frac{P}{1 - P} = \beta_0 + \boldsymbol{\beta}^\top \mathbf{x}.

其中 β\boldsymbol{\beta} 是待估系数向量,β0\beta_0 是截距。log ⁣P1P\log\!\frac{P}{1-P} 称为 log-odds,它把 [0,1][0,1] 上的概率映射到全实数轴。

公式背后的会计直觉是:模型给每个特征一个权重,把所有特征按权重加起来得到 log-odds,再用 sigmoid 把 log-odds 翻译回概率。系数 βj\beta_j 的解释是"特征 xjx_j 每增加一个单位,log-odds 增加 βj\beta_j",等价于"舞弊优势比 odds ratio 乘以 eβje^{\beta_j}"。这种"权重 + 加和 + 压缩"的结构和 M-Score 的"权重 + 加和"只差最后一步压缩,但因为权重是从数据里学出来的而不是查表查来的,模型可以适配新样本。

图 3·1 Dechow F-Score 逻辑回归的整体管道:七个会计比率分别度量应计质量、绩效压力与融资动机;权重 βj\beta_j 由 Bao 训练集 1991–2002 用 MLE 估出,线性组合得到 log-odds zz;sigmoid 函数把 zz 压回 [0,1][0,1] 得到预测舞弊概率 p^\hat p;F-Score 等于 p^\hat p 除以训练期无条件舞弊率 pˉ\bar p,本数据 pˉ0.83%\bar p \approx 0.83\%,下节实证给出。完整 TikZ 结构图详见 PDF 全文。

逻辑回归用最大似然估计拟合,简称 MLE。给定训练样本 (xi,yi)(\mathbf{x}_i, y_i),参数选择让对数似然函数取最大值。这个优化是凸的,没有局部最优解,迭代算法收敛快,是它能在 1980 年代低算力时代普及的根本原因。R 的 glm 默认用 IRLS 算法解 MLE,Python 的 sklearn 默认带 L2 正则,要逼近 R 的解需要把惩罚强度参数 CC 设成一个极大值,并换用 newton-cg 解算器。这一节的代码会演示这件事。

Dechow F-Score 的设计

Dechow、Ge、Larson 和 Sloan 在 2011 年的论文里做了一件事:把当时已知的舞弊先行指标整理成一个更系统的特征集,用 1982–2005 年 SEC 发布的 AAER 标记的 676 家舞弊公司样本训练逻辑回归,得到一个被后来文献广泛引用的得分函数。这套特征集分三类:应计质量、绩效压力、融资动机。

应计质量类有三个变量。第一个是 RSST 应计的同比变化,对应 Bao 字段里的 ch_rsst。Richardson、Sloan、Soliman、Tuna 在 2005 年发现,把传统总应计扩展到包含非现金净营运资本、非流动经营资产和非流动经营负债三块后的"全口径"应计与未来盈余反转更相关。应计金额本身越大,公司在收入确认与费用资本化上动用的会计估计弹性越大,越容易给舞弊提供操作空间。第二个是应收账款的同比变化 dch_rec。应收账款相对于销售异常增长,是收入虚增的经典信号:卖了货但收不到钱,往往意味着收入是用客户授信硬撑出来的。第三个是存货的同比变化 dch_inv。存货相对于销售异常累积,是销货成本被压低的嫌疑信号;公司把本该结转的成本留在存货账户里,当期净利润就被人为推高。

绩效压力类有两个变量。soft_assets 衡量软性资产占总资产的比例,软性资产是除现金、PPE 之外的中间科目,比如应收、存货、商誉等。这些科目的账面价值依赖会计估计,估计弹性越大,操纵空间越大。ch_roa 是资产回报率的年度变化。Dechow 等人发现,舞弊公司在被处罚年度往往伴随 ROA 的同比下滑,反映"业绩压力催生造假动机":公司越是经营不下去,越有动机美化报表。这个方向让 ch_roa 的回归系数应当为负。

融资动机类有两个变量。ch_cs 是现金销售相对于销售总额的年度变化,反映收入结构里"硬通货"占比的变动;issue 是个 0/1 哑变量,标记公司当年是否新发权益或债务。当年要发新股发新债的公司,有强烈动机把当期报表做得好看,让市场愿意以较高价格接盘。

七个变量加起来是 Dechow 2011 论文 Table 7 Model 1 的预测器集合。原文的回归系数被用来构造 F-Score:把模型预测的舞弊概率除以样本无条件舞弊率,得到一个相对放大倍数。F-Score 大于 1 意味着这家公司的预测舞弊概率高于平均,大于 1.85 是 Dechow 给出的"高风险"经验阈值,大于 2.45 是"非常高风险"阈值。这套阈值在 Bao 数据上是否仍然合用,下一节用代码检验。

在 Bao 数据上的实现

我们先按 Bao 协议切训练 / 验证 / 测试三段,然后分别拟合 Model A 和 Model B。Model A 把 28 个原始 Compustat 变量与 14 个衍生比率全放进右边,共 42 个特征;Model B 只用 Dechow 七变量。两个模型都在切分前先做 NA 过滤,因为一行只要任一特征缺失,逻辑回归无法处理这一行。这是逻辑回归相对树模型的明显短板,第 5 章会讨论。

library(tidyverse)
library(pROC)
set.seed(2026)

d <- read_csv(here::here("data", "bao2020_full.csv"),
              show_col_types = FALSE)

raw_vars <- c("act","ap","at","ceq","che","cogs","csho","dlc","dltis",
              "dltt","dp","ib","invt","ivao","ivst","lct","lt","ni",
              "ppegt","pstk","re","rect","sale","sstk","txp","txt",
              "xint","prcc_f")
ratio_vars <- c("dch_wc","ch_rsst","dch_rec","dch_inv","soft_assets",
                "ch_cs","ch_cm","ch_roa","issue","bm","dpi","reoa",
                "EBIT","ch_fcf")
all_vars    <- c(raw_vars, ratio_vars)
dechow_vars <- c("ch_rsst","dch_rec","dch_inv","soft_assets",
                 "ch_cs","ch_roa","issue")

# Model A:42 特征全集,先丢有 NA 的行,再切
d_full <- d %>% drop_na(all_of(all_vars))
trA <- d_full %>% filter(fyear >= 1991, fyear <= 2002)
teA <- d_full %>% filter(fyear >= 2009, fyear <= 2014)
mA  <- glm(reformulate(all_vars, "misstate"),
           data = trA, family = binomial)
predA <- predict(mA, newdata = teA, type = "response")

# Model B:Dechow 七变量
d_dech <- d %>% drop_na(all_of(dechow_vars))
trB <- d_dech %>% filter(fyear >= 1991, fyear <= 2002)
teB <- d_dech %>% filter(fyear >= 2009, fyear <= 2014)
mB  <- glm(reformulate(dechow_vars, "misstate"),
           data = trB, family = binomial)
predB <- predict(mB, newdata = teB, type = "response")
结果解读样本量与切分

Model A 全集 42 特征至少有 19,562 行存在缺失,丢掉后剩下 126,483 行;按 Bao 协议切分得到训练 63,930 行含舞弊 537、验证 30,777 行含舞弊 250、测试 27,628 行含舞弊 107。Model B 七变量缺失少一些,丢 16,613 行,剩 129,432 行,测试 28,636 行舞弊数同样为 107。两边测试集的阳性数都是 107,比第 1 章原始 112 少 5 例,差异来自这 5 家公司在所选特征上有缺失。后面的 AUC 是基于这 107 个真阳性的可比较结果。

系数符号方向的会计直觉检查

Model B 七变量在 Bao 训练集上的拟合系数列在下表。每个系数的会计直觉方向都可以预先写下来,再去和 R 输出对照。

表 3·1 Dechow 七变量在 Bao 训练集 1991–2002 上的逻辑回归系数

变量估计Std. Errorzzpp预期方向
(Intercept)7.365-7.3650.27027.29-27.29<0.001<0.001
ch_rsst+0.548+0.5480.142+3.85+3.85<0.001<0.001+
dch_rec+1.485+1.4850.478+3.10+3.100.0020.002+
dch_inv+0.515+0.5150.643+0.80+0.800.420.42+
soft_assets+2.082+2.0820.198+10.52+10.52<0.001<0.001+
ch_cs+0.055+0.0550.030+1.83+1.830.0670.067+
ch_roa0.419-0.4190.1472.85-2.850.0040.004-
issue+1.353+1.3530.241+5.62+5.62<0.001<0.001+

七个变量的符号方向全部与会计直觉一致。soft_assets 是数值上最强的预测器,系数 +2.08+2.08 对应优势比 e2.088.0e^{2.08} \approx 8.0;软性资产占比每提高一个百分点,舞弊优势比放大 8 倍。issuech_rsst 紧随其后,对应"当年发新股发新债"和"全口径应计大幅增长"两条经典舞弊路径。ch_roa 系数为负且显著,确认"业绩压力催生造假"的方向。两个边缘信号是 dch_inv,不显著,与 ch_csp=0.067p = 0.067dch_inv 的不显著有点意外,可能与 Bao 数据样本期与 Dechow 原文不重叠有关;2008 年以后零售与制造业存货管理普及 ERP,存货异常增长作为舞弊信号的判别力被自然削弱。

停下来想一想。 如果你要在审计场景里用 F-Score 做风险筛查,你会更信任系数的方向,还是它的具体数值?把训练样本期 1991–2002 和应用期 2009–2014 之间发生的所有制度变化、技术变化、行业结构变化都算进来,答案就清楚了:方向比数值更稳健。这也是为什么 Dechow 论文给 F-Score 设的两个阈值,1.85 对应高风险,2.45 对应非常高风险,一直被后续文献沿用,但具体的回归系数随每篇复刻论文样本变动而漂移。

性能评估与案例公司打分

Model A 与 Model B 在测试集 2009–2014 共 107 例舞弊上的四指标列在下表。

表 3·2 两种逻辑回归模型在测试集 2009–2014 上的性能

模型AUCNDCG@100Recall@1%Precision@1%
Model A 全 42 特征0.69660.05100.05610.0217
Model B Dechow 70.67520.00000.00930.0035
结果解读

两个模型都明显跑赢第 1 章零模型基线 AUC = 0.500 和第 2 章 M-Score 的 AUC = 0.5399。Model A 加了 35 个原始与衍生变量后,AUC 提升 0.021 个点;前 1% 名额共 277 行里命中 6 个真舞弊,Recall@1% 达 5.61%。Model B 在 AUC 上只低 0.021,但 NDCG@100 = 0 暴露一个严重问题:前 100 名里没有任何一个真舞弊。换句话说,Dechow 七变量在 Bao 测试期上对最顶端的排序毫无判别力。这一点和原文报告的训练集表现差距很大,是后续章节 LASSO 与树模型必须解决的痛点。

两家标志性案例公司在 Model A 和 Model B 下的得分列在下表。Model B 的预测概率乘以无条件舞弊率倒数后就是 F-Score。

表 3·3 Enron 2000 与 Tyco 2000 在两种逻辑回归下的打分

案例真实标签Model A p^\hat pModel B p^\hat pF-Score
Enron 2000 (gvkey=6127)10.93680.01802.17
Tyco 2000 (gvkey=10787)10.15840.01351.63

Enron 2000 在 Model A 下被判定为高度可疑,预测概率 0.937,远超审计场景的任何合理阈值;Model B 给的预测概率虽然只有 1.8%,但 F-Score = 2.17 落在 Dechow 1.85 阈值之上,按原文标准属于"高风险"区间。两个模型对 Enron 都给出了"该查"的结论。Tyco 2000 的情况更复杂:Model A 只给 0.158,Model B 给 0.014,对应 F-Score = 1.63 低于 1.85 阈值。Tyco 是规模化连环并购公司,被处罚的舞弊主要是高管私人开支报销与并购溢价分摊扭曲,纯财务比率信号对这类舞弊的敏感度天然较低。这件事呼应第 1 章的 noisy positive 讨论:模型识别不出 Tyco,不一定是模型错,可能是 Tyco 的舞弊信号根本不在七个比率覆盖的维度里。

雷区逻辑回归在极度不平衡数据上的退化

逻辑回归在极度不平衡数据上有一个退化倾向:MLE 优化目标是平均对数似然,而样本里 99.34% 的观测都是阴性,损失函数的主要项来自把阴性样本预测为阴性。模型最优解会把所有样本的预估概率压在无条件舞弊率附近,本数据约 0.66%–0.83%,即使最显著的特征对应的优势比已经达到 8 倍。结果是排序仍然有判别力,AUC 高于 0.5,但绝对预测概率被系统性低估,无法直接拿来做"是否调查"的二元决策。Python 里把 class_weight 设成 'balanced' 是常见的部分修正,但实测对 AUC 与 NDCG 几乎无影响,本章数据上 AUC 从 0.6752 变到 0.6747。真正解决这个问题要等第 7 章的 RUSBoost:欠采样多数类后再做提升,把训练分布人为推向平衡。

R 与 Python 在两个模型上的所有数字一致到小数点后 4 位。Python 的 sklearn 默认带 L2 正则,要逼近 R 的 MLE 解需要把惩罚强度参数 CC 设成 10810^8 并换用 newton-cg 解算器;如果继续用默认 lbfgs 解算器,42 特征的量纲差异会让 lbfgs 不收敛,最终给出一个明显劣于 R 的解。这里的量纲差异指原始 Compustat 字段从几个数量级到亿美元,衍生比率多在 [1,1][-1, 1] 区间。这是 Python 实现里最容易踩的坑。

本章累积对比表

表 3·4 第 3 章累积方法对比

方法AUCNDCG@100Recall@1%Precision@1%可解释性局限
全部预测为非舞弊0.5000.0000.0000.000完全可解释无判别力
Beneish M-Score, 第 2 章0.53990.0000.01100.0049高,八变量加权权重 1992 年固定,无学习能力
逻辑回归 Model A 全 42 特征0.69660.05100.05610.0217中,系数可读但变量多对量纲敏感、共线性、需手工 NA 处理
逻辑回归 Model B Dechow 70.67520.00000.00930.0035高,七变量会计直觉清晰顶端排序失灵;样本期外漂移大

第 4 章把 Model A 的 42 特征加上 LASSO 与 Elastic Net 正则化,看看自动特征选择能不能在 AUC 不下降的前提下,把模型缩到一个 7 到 12 个变量、可解释性接近 Dechow 七变量、判别力接近 Model A 的紧凑版本。

本章知识地图

表 3·5 第 3 章核心概念与常见误解

核心概念核心内容常见误解为什么错
逻辑回归通过 sigmoid 把线性组合的 log-odds 映射回概率;用 MLE 拟合系数逻辑回归是分类器,输出 0/1 标签逻辑回归输出的是连续概率,二元化要靠用户选阈值;阈值选择本身是单独的决策
log-oddslog ⁣P1P\log\!\frac{P}{1-P},把 [0,1][0,1] 概率映射到全实数轴log-odds 增加 1 等于概率增加 1log-odds 与概率是非线性关系;同样增加 1 个单位的 log-odds,在 P=0.5P=0.5 附近概率变化大,在 P=0.99P=0.99 附近变化小
优势比 odds ratioexp(βj)\exp(\beta_j),特征 xjx_j 增加一个单位对应优势比的乘数优势比就是相对风险优势比与相对风险只在 PP 接近 0 时近似相等;舞弊问题里 P0.007P \approx 0.007,两者数值确实接近,但概念上不同
F-ScoreDechow 七变量逻辑回归预测概率除以无条件舞弊率得到的相对放大倍数F-Score 越高一定越可疑F-Score 阈值 1.85 / 2.45 是基于 Dechow 原文 1982–2005 样本得到的,迁移到新样本期阈值需要重校准
最大似然估计 MLE选择参数让训练样本的对数似然最大化;逻辑回归的 MLE 是凸优化R 的 glm 与 Python 的 sklearn 给出相同的解Python 默认带 L2 正则;要逼近 R 的无正则 MLE,需要 CC 设为极大值并换 newton-cg 解算器
极度不平衡退化舞弊率 <1%<1\% 时,逻辑回归的预测概率被系统性压低到无条件舞弊率附近class_weight='balanced' 就能解决重加权能改变绝对概率水平,但对排序型指标 AUC、NDCG 几乎无影响;真正的解需要 RUSBoost 这类欠采样 + boosting 方法
Model A vs Model B特征集越大测试集 AUC 越高,但顶端排序的变化更复杂特征多一定更好Model A 多用 35 个变量,AUC 只提升 0.021;过拟合风险与解释性损失需要正则化或变量选择来平衡
样本期漂移Dechow 1982–2005 训练,Bao 2009–2014 测试,七变量符号方向稳定但数值漂移原文报告的高风险阈值可以原封不动用审计制度变化、行业结构变化、ERP 普及让某些变量的判别力随时间衰减;阈值需要在新样本上重校