准确率陷阱:模型准确率 65%,但什么都不做是 73%

261次阅读
没有评论

基础比率谬误:流失率仅 26.54%,全猜”不流失”的基线就有 73.46%

数据:IBM / UCI Telco Customer Churn 电信客户流失(7,043 条,公开数据)(公开数据集,可自行下载复现)


先看一个场景

算法同学汇报:“我们的流失预测模型,准确率 65%。”

听上去还行。但先别急着判断——问一句:这个业务里,什么都不做能有多少准确率?

答案是 73.46%


用真实数据算一遍

数据:7,043 名电信客户,其中流失 1,869 人,流失率 26.54%

最简单的策略:所有人都预测”不流失”。

猜"不流失"的人里有 73.46% 真的没流失
→ 准确率 73.46%

这就是及格线。任何模型达不到它,还不如不做。

现在看那个”月付就预测流失”的规则:

指标 数值
准确率 65.44%
精确率 42.7%
召回率 88.6%
F1 57.6%

准确率陷阱:模型准确率 65%,但什么都不做是 73%

准确率 65.44%,低于基线 73.46%。 这个规则比”什么都不做”还差。


但换个指标,它又不差

准确率陷阱:模型准确率 65%,但什么都不做是 73%

一个模型,四个指标给出四个答案:

  • 准确率 65.44% → 低于基线,看着很差

  • 召回率 88.6% → 抓到了 88.6% 的真实流失,看着很好

  • 精确率 42.7% → 报警的人里只有 42.7% 真流失,一半是误报

哪个是对的?都对,取决于你要干什么。

准确率陷阱:模型准确率 65%,但什么都不做是 73%


拆开看那 7,043 个人

准确率陷阱:模型准确率 65%,但什么都不做是 73%

真流失且被抓到  1655 人
误报            2220 人   ← 白忙
漏掉            214 人
正确排除        2954 人

误报 2220 人,比抓对的 1655 人还多。 如果每打一个挽留电话有成本,这个模型会浪费一半人力。

但另一方面,它抓到了 88.6% 的流失——如果流失代价很高,这个召回率是有价值的。


评估前,先算一条基线

准确率陷阱:模型准确率 65%,但什么都不做是 73%

  1. 算基础比率:流失率多少?本例 26.54%

  2. 算基线准确率:全猜多数类 = 73.46%。模型必须超过它

  3. 看精确率:报警的人里多少是真的?决定人力成本

  4. 看召回率:真实的流失抓到多少?决定漏掉的损失

  5. 算提升倍数:42.7% ÷ 26.54% = 1.61 倍(比瞎猜准多少)

第 5 条最能说明价值——本例精确率 42.7%,是瞎猜(26.54%)的 1.61 倍。这个数比”准确率 65%”有意义得多。


什么时候用哪个指标

场景 看什么 原因
流失预测、疾病筛查 召回率 漏掉代价高
垃圾邮件、风控拦截 精确率 误报代价高
两类代价差不多 F1 平衡
类别极度不平衡 别看准确率 会被基础比率骗

规律:正例占比越小,准确率越没用。 流失率 26% 时准确率已经会骗人;如果是千分之一的欺诈检测,99.9% 准确率的模型可能一个都没抓到。


附:可运行代码

数据集:IBM / UCI Telco Customer Churn 电信客户流失(7,043 条,公开数据)

import pandas as pd

df['churn'] = (df['Churn'] == 'Yes').astype(int)
base = df['churn'].mean()
print('流失率 %.2f%%' % (100 * base))
print('什么都不做(全猜不流失)准确率 %.2f%%' % (100 * (1 - base)))

# 一个简单规则:月付就预测流失
pred = (df['Contract'] == 'Month-to-month').astype(int)
acc  = (pred == df['churn']).mean()
tp = ((pred == 1) & (df['churn'] == 1)).sum()
fp = ((pred == 1) & (df['churn'] == 0)).sum()
fn = ((pred == 0) & (df['churn'] == 1)).sum()
prec, rec = tp / (tp + fp), tp / (tp + fn)
print('准确率 %.2f%%  精确率 %.1f%%  召回率 %.1f%%'
      % (100*acc, 100*prec, 100*rec))
print('提升倍数 %.2f 倍' % (prec / base))

跑一遍你会看到:准确率 65.44% < 基线 73.46%,但精确率是瞎猜的 1.61 倍。

如果你也在做类似的东西,欢迎交流,我这边有完整实现,可以发你参考。


正文完
 2
评论(没有评论)