# 数据分析 · 第 04 篇|诊断性分析与归因 > 系列:project / 数据分析(共 12 篇)|AI生成|2026-10-27|codebuddy **这一篇讲什么** 第 03 篇回答「现在是什么样」,这一篇处理描述之后最难的一步:数字变了,为什么变。诊断性分析的价值不在于给出一个听起来合理的解释,而在于把「可能是」压缩成「大概率是,而且我知道下一步怎么验证」。本篇按真实工作的顺序展开:先做异常核查,因为相当一部分「异常」其实是口径、埋点、时区、退款造成的假信号;再做加法拆解、乘法拆解和维度拆解,用北辰优选 GMV 下降 8% 走完一棵完整的拆解树;接着讲下钻顺序、相关与因果的四类陷阱、五种归因模型、假设验证和 5 Whys;最后给出诊断报告的六段式结构与三条纪律。读完应该能做到:拿到一个异常数字,先怀疑数据,再怀疑结构,最后才怀疑业务。 ## 一、先别急着解释:确认「数是不是真的」 周一早上九点,运营群里弹出一句「GMV 环比跌了 8%,是不是大促结束了」。十分钟后,三种解释已经出现:竞品降价、天气转凉、投放预算砍了。这三种解释可能都对,也可能全错,因为它们都跳过了第一步——**这个 8% 是真的吗**。 诊断性分析最常见的浪费,是花两天时间解释一个并不存在的下跌。数据链路上有六类假信号,每一类都能凭空造出一个「异常」。 | 检查项 | 典型问题 | 怎么查 | 命中后怎么办 | | --- | --- | --- | --- | | 口径变化 | 分子分母被改过;退款是否计入;是否含运费 | 对比指标定义文档与看板 SQL | 统一口径后重算,历史数据同步回刷 | | 埋点变更 | 事件重命名、SDK 升级、上报丢失 | 看事件量的日粒度曲线是否有台阶 | 用相邻事件量交叉验证,必要时补数 | | 时区与跨天 | 服务器用 UTC,报表按本地日期 | 同一批订单按两种时间归日,看差额 | 明确归日规则,写进指标字典 | | 退款与取消 | 只统计 paid,忽略跨期退款 | 毛 GMV 与净 GMV 分开算 | 同时报两个数,说明差异 | | 重复计算 | 一对多 join 把订单放大;多端重复上报 | 按主键 group by 数行数 | 先去重再聚合,或改用子查询 | | 数据延迟 | T+1 任务未跑完、迟到数据未回补 | 看分区是否完整、最新分区时间 | 等数据齐再下结论,或标注「未完整」 | 北辰优选的这次异常,核查从三条 SQL 开始。注意这三条查询只用 users、orders、events 里已有的字段,不需要额外建表,目的是先排除「数据本身有问题」这个最廉价的可能性。 ```sql -- 1) 订单粒度是否被放大:一个 order_id 是否出现多行 SELECT order_id, COUNT(*) AS cnt FROM orders GROUP BY order_id HAVING COUNT(*) > 1 ORDER BY cnt DESC; -- 2) 状态口径:paid / refunded / cancelled 各占多少 SELECT status, COUNT(*) AS orders, SUM(amount) AS amount FROM orders WHERE order_date >= '2026-09-01' AND order_date < '2026-10-01' GROUP BY status; -- 3) 同一用户同一天多笔:是真实复购还是重复上报 SELECT user_id, order_date, COUNT(*) AS n, SUM(amount) AS amt FROM orders WHERE status = 'paid' AND order_date >= '2026-09-01' AND order_date < '2026-10-01' GROUP BY user_id, order_date HAVING COUNT(*) >= 5 ORDER BY n DESC LIMIT 30; ``` 第一条查主键重复,第二条查状态结构,第三条查可疑的集中下单。如果三条都干净,还要问两个问题:`order_date` 是按服务器时区还是用户本地时区落库的?9 月 30 日 23 点之后的订单落在哪一天?这两个问题在大促、月末、跨年时经常制造出 1%—3% 的假波动。 核查的结论必须写成一句话,而不是「应该没问题」。比如:**口径未变、无重复主键、退款率与上月持平(3.1% 对 3.0%),因此 100 万元的下降是真实发生的**。这句话后面所有的分析才有地基。 ## 二、加法拆解与乘法拆解:把大数字拆成能查的小数字 确认数是真的之后,第一件事不是找原因,而是把 100 万元拆成几个可以分别去查的部分。拆解的方向由指标的定义决定,常见两种。 **加法拆解**适合「总量由几类构成」的指标。北辰优选的 GMV 可以按新老客拆: GMV = 新客 GMV + 老客 GMV | 分项 | 8 月(万元) | 9 月(万元) | 变化(万元) | 贡献占比 | | --- | --- | --- | --- | --- | | 新客 GMV | 500 | 420 | -80 | 80% | | 老客 GMV | 750 | 730 | -20 | 20% | | 合计 | 1250 | 1150 | -100 | 100% | 这张表一眼就能改变讨论方向:老客几乎没动,问题在新客。继续沿新客往下拆,新客 GMV 又能拆成「新客数 × 新客客单价」:新客数从 10,000 降到 8,400(-16%),新客客单价 500 元持平。于是问题从「为什么 GMV 跌」收敛成「为什么 9 月新客少了 1,600 人」。这是诊断最重要的动作——**每拆一层,问题的范围就小一圈**。 **乘法拆解**适合「总量由几个比率相乘」的指标。电商最常用的一条: GMV = UV × 支付转化率 × 客单价 | 因子 | 8 月 | 9 月 | 变化率 | | --- | --- | --- | --- | | UV(访问用户数) | 500,000 | 520,000 | +4.0% | | 支付转化率 | 3.20% | 2.95% | -7.8% | | 客单价(元) | 781.25 | 750.00 | -4.0% | | GMV(万元) | 1250 | 1150 | -8.0% | 三个因子的变化率分别是 +4.0%、-7.8%、-4.0%,看起来「谁都没跌 8%」,但 GMV 就是跌了 8%,因为乘法里的小幅下降会累积。这时候不能看变化率,要看**贡献度**:固定一个替换顺序,每次只把一个因子换成当期值。 | 替换步骤 | 替换后 GMV(万元) | 本步贡献(万元) | 占总变化 | | --- | --- | --- | --- | | 基准 | 1250.0 | — | — | | UV 换为 52 万 | 1300.0 | +50.0 | -50% | | 转化率换为 2.95% | 1198.4 | -101.6 | +102% | | 客单价换为 750 | 1150.5 | -47.9 | +48% | | 合计 | 1150.5 | -99.5 | 100% | 读法是:UV 增长本来能带来 +50 万,转化率下滑吃掉了 101.6 万,客单价下滑又吃掉 47.9 万,三者相抵是 -99.5 万。**转化率是主因,UV 的增长掩盖了它的一半杀伤力**。如果只看「UV 涨了 4%」就下结论说流量健康,就会错过真正的问题。 这里有一个必须提醒的技术细节:逐项替换法的贡献度**依赖替换顺序**。先换 UV 和先换客单价,得到的分解结果不同。想消除顺序依赖,可以改用对数分解: ln(GMV₁/GMV₀) = ln(UV₁/UV₀) + ln(CVR₁/CVR₀) + ln(AOV₁/AOV₀) 把每个对数项除以总对数变化,就是该因子的贡献占比。北辰优选这组数算出来,UV 约 -47%(正向抵消)、转化率约 +98%、客单价约 +49%,与上表方向一致但数值更稳定。代码示意如下,可以直接替换成自己的数。 ```python #乘法拆解的两种贡献度算法(示意,数值为虚构教学数据) import numpy as np cur = {"uv": 520_000, "cvr": 0.0295, "aov": 750.00} base = {"uv": 500_000, "cvr": 0.0320, "aov": 781.25} #方法一:逐项替换,结果与顺序有关 state, prev = dict(base), 1250.0 for k in ["uv", "cvr", "aov"]: state[k] = cur[k] now = state["uv"] * state["cvr"] * state["aov"] / 10_000 print(f"{k:>4} 贡献 {now - prev:>8.1f} 万元") prev = now #方法二:对数分解,可加且与顺序无关(简化版) g = {k: np.log(cur[k] / base[k]) for k in cur} total = sum(g.values()) for k, v in g.items(): print(f"{k:>4} 对数贡献占比 {v / total:>7.1%}") ``` ## 三、按维度拆:渠道、城市、品类、新老客、机型 乘法拆解告诉你「是转化率的问题」,维度拆解告诉你「是谁的转化率」。北辰优选把 100 万元按四个维度各切一遍,得到四张都加总为 -100 万的表。 | 渠道 | 8 月 | 9 月 | 变化 | 贡献占比 | | --- | --- | --- | --- | --- | | 信息流 | 520 | 458 | -62 | 62% | | 搜索 | 300 | 282 | -18 | 18% | | 老客推荐 | 180 | 168 | -12 | 12% | | 自然流量及其他 | 250 | 242 | -8 | 8% | | 合计 | 1250 | 1150 | -100 | 100% | 同样一笔 100 万,按城市拆是「一线 -30、新一线 -25、二线 -28、三线及以下 -17」;按品类拆是「生鲜 -55、美妆 -30、家居 -25、数码 +10」;按机型拆是「安卓低端 -70、安卓中高端 -20、iOS -10」。四张表都成立,因为它们是对同一个总量的不同切分。 新手最容易犯的错,是把四张表的「主要原因」相加,得出「信息流 + 生鲜 + 低端安卓 + 一线城市共同导致下跌」——这是同一批订单被数了四遍。正确的做法是**交叉**:把渠道和机型放在一起看,才会发现信息流的跌幅集中在安卓低端机(-52 万,占信息流跌幅的 84%),而生鲜的跌幅又主要来自这批用户的订单结构。维度拆解的目的不是列清单,是找到那个「一交叉就收敛」的切片。 另一个必须警惕的现象是**变化率与贡献度的错位**。假设「宠物用品」这个品类跌了 50%,听起来触目惊心,但它 8 月只有 6 万元,对 100 万的下跌只贡献 3 万。反过来,生鲜只跌了 9%,却贡献了 55 万。所以在诊断会上,第一个该问的问题不是「哪个跌得最狠」,而是「哪个贡献得最多」。变化率回答「哪里异常」,贡献度回答「哪里重要」,两者都要,但排序不能反。 ## 四、下钻顺序:总体 → 维度 → 链路 → 用户 → 时间 拆解是横向铺开,下钻是纵向深入。有五层,每层只问一个问题。 | 层级 | 要回答的问题 | 典型产出 | 常见误判 | | --- | --- | --- | --- | | 总体 | 跌了多少,是哪个指标,是否季节性 | 一句话量化事实 | 把正常波动当异常 | | 维度 | 哪个切片的贡献最大 | 贡献度排序表 | 用变化率代替贡献度 | | 链路 | 漏斗的哪一步断了 | 分步转化率对比 | 只看末端转化率 | | 用户 | 是所有人都在跌,还是某类人 | 新老、频次、价值分层 | 用整体均值掩盖分层差异 | | 时间 | 是突变还是渐变,断点在哪天 | 日粒度曲线与断点位置 | 用月度数据掩盖单日故障 | **链路层**要按事件表还原漏斗:曝光 → 访问(view)→ 加购(add_cart)→ 结算(checkout)→ 支付(pay)。北辰优选 9 月的漏斗是:访问 52 万 → 加购率 18.2%(8 月 18.5%,基本持平)→ 结算率 41%(8 月 42%)→ 支付率 61%(8 月 72%)。前三步都正常,断在最后一步,支付率掉了 11 个百分点。到这里,「转化率下降」被定位成「支付环节流失」。 **用户层**要问:是所有人都掉,还是只有一部分人掉。把 9 月支付率按新老客拆:新客从 58% 掉到 44%,老客从 79% 掉到 77%。老客几乎没动,新客掉了 14 个百分点。再按机型拆新客:iOS 新客 57%→55%,安卓中高端 56%→52%,安卓低端 59%→38%。**跌幅高度集中在安卓低端机的新客**,这个切片的形状已经非常像技术问题,而不像「用户不想买」。 **时间层**决定是突变还是渐变。把安卓低端机的支付率画成日曲线:9 月 1—7 日稳定在 58% 左右,9 月 8 日突然掉到 40%,之后一直在 38%—42% 之间。突变意味着一次事件(发版、配置变更、第三方服务故障、政策),渐变意味着结构性变化(竞争、价格、供给)。9 月 8 日这个断点,把排查范围从「一个月」压缩到「那一天发生了什么」。 五层走完,最初的「GMV 跌了 8%」变成了一句可验证的话:**9 月 8 日起,安卓低端机新客在支付页的失败率从 1.2% 升到 6.8%,导致新客支付率下降 14 个百分点,进而造成 GMV 减少约 100 万元**。这句话里有时间、有切片、有机理、有量级,随便哪个环节错了都能被证伪——这才是诊断该有的样子。 ## 五、相关不是因果:四种会让你写错结论的陷阱 诊断报告最容易出事的地方,是把「同时发生」写成「导致」。有四种陷阱,每一种都能让一个看起来严密的分析彻底跑偏。 **混淆变量**。观察到「投广告后 GMV 涨」,于是得出结论「广告有效」。但 9 月同时发生的事还有:大促开始、平台发放跨店满减、竞品缺货。这三件事都能单独推高 GMV。广告投放期和大促期高度重叠,两者在数据上无法区分。识别方法是问一句:**有没有第三个变量同时影响了原因和结果**。如果有,就要么控制它(分层、回归加协变量),要么用实验把它随机掉。 **反向因果**。也可能是「因为预计 GMV 会涨,所以加大了投放」——预算本来就跟大促节奏走。数据上广告和 GMV 正相关,因果方向却完全相反。判断顺序只能靠时间:投放决策发生在 GMV 上涨之前,还是之后?如果预算审批单的日期晚于销量起势的日期,这条因果链就该反过来写。 **选择偏差**。只对「高潜人群」投放,然后发现投放组转化率远高于未投放组。这不是广告的效果,是挑选的效果——高潜人群本来就会买。解决办法是找一个可比对照组,或者做随机分流。凡是「按某种规则挑人」的对比,都要先问:这个规则本身是不是就和结果相关。 **辛普森悖论**。这是最隐蔽的一种。北辰优选的渠道复盘里,搜索渠道整体转化率 4.0%,信息流只有 2.76%,看起来应该把预算全搬到搜索。但分新老客一看,信息流在两个分层里都更高。 | 渠道 | 新客转化率 | 老客转化率 | 新客占比 | 整体转化率 | | --- | --- | --- | --- | --- | | 搜索 | 2.0% | 4.5% | 20% | 4.00% | | 信息流 | 2.2% | 5.0% | 80% | 2.76% | 搜索整体高,只是因为它的老客占比高达 80%,而老客转化率天然更高。**分组结论和整体结论相反**,原因是分组权重不同。这种结构在「渠道对比」「版本对比」「地区对比」里极其常见,凡是看到整体和分组方向不一致,就要先检查权重,而不是急着选一个相信。 区分相关与因果,实操上有三道门:第一,时序对不对(因在前、果在后);第二,有没有剂量反应(投得多是否效果更大);第三,能不能排除竞争解释(同期还有什么变了)。三门都过,可以写「很可能是」;只过一门,只能写「相关」。第五篇会用实验和准实验方法,把「很可能」再往前推一步。 ## 六、归因模型:五次点击,功劳该给谁 前面讲的是「指标为什么变」,归因模型解决的是另一个问题:**一笔转化发生了,功劳怎么分给路上的各个触点**。北辰优选有个用户,8 天内接触了四个触点后下单 300 元: | 触点 | 时间 | 动作 | 最后点击 | 首次点击 | 线性 | 时间衰减 | 位置归因 | | --- | --- | --- | --- | --- | --- | --- | --- | | 信息流曝光 | 第 1 天 | 看到素材 | 0 | 300 | 75 | 51 | 120 | | 搜索点击 | 第 3 天 | 搜品牌词 | 0 | 0 | 75 | 63 | 30 | | 详情页加购 | 第 6 天 | 加购物车 | 0 | 0 | 75 | 84 | 30 | | 优惠券点击 | 第 8 天 | 领券并支付 | 300 | 0 | 75 | 102 | 120 | | 合计 | — | — | 300 | 300 | 300 | 300 | 300 | 同一笔订单,五种规则给出五个「真相」。时间衰减用的是 w = 2^(-(T-t)/h),半衰期 h 取 7 天,权重归一化后分配。位置归因是首末各 40%、中间触点均分 20%。 | 模型 | 分配规则 | 适合回答 | 主要盲点 | | --- | --- | --- | --- | | 最后点击 | 100% 给最后一次触点 | 直接转化渠道的考核 | 完全无视种草,容易高估搜索 | | 首次点击 | 100% 给第一次触点 | 拉新渠道的价值评估 | 无视临门一脚,容易高估品牌广告 | | 线性 | 所有触点平均分 | 长链路、多触点的品牌曝光 | 把「路过」和「推动」等同 | | 时间衰减 | 越近权重越高 | 决策周期短的品类 | 半衰期是人为设定,可调出不同答案 | | 位置归因 | 首末各 40%,中间分 20% | 既要拉新又要转化的平衡视角 | 中间触点的真实作用被压扁 | 用归因模型要记住一句话:**它是分配规则,不是因果测量**。换一个模型,预算就会从搜索搬到信息流,但用户行为一点没变。所以归因结果适合用来「对齐内部对渠道价值的共识」,不适合用来「证明某个渠道真的有效」。要证明有效性,还是得回到实验或准实验。 至于营销组合模型(MMM),可以把它理解成「在更粗的粒度上做归因」:用周或月的时间序列,把销量拆成基线、季节性、价格、各渠道投放几部分,通过回归估计每个渠道的边际贡献。它的优点是能覆盖线下和无法追踪的曝光,缺点是粒度粗、需要长期数据、容易把相关当因果。实践中常见做法是 MMM 定预算大盘,实验定单渠道的边际效率,两者互相校准。 ## 七、假设验证与 5 Whys:把猜测变成可检验的命题 诊断到链路层之后,通常会剩下两三个候选解释。此时不要开会投票,要把每个解释写成可证伪的假设,然后设计最小验证动作。 | 假设 | 预期证据 | 可能的反证 | 最小验证动作 | 成本 | | --- | --- | --- | --- | --- | | H1 支付页改版引发技术故障 | 失败率随版本、机型、网络分层出现差异;回滚后恢复 | iOS 与高端机完全无变化,说明与版本无关 | 按「版本 × 机型 × 网络」三向分组看失败率;回滚 10% 流量观察 48 小时 | 1 人日 | | H2 券力度下降导致购买意愿降低 | 用券订单占比下降,且未用券用户转化率不变 | 未用券用户转化率同步下降,说明不是券的问题 | 对比同券档位用户与无券用户的支付率变化 | 0.5 人日 | | H3 渠道结构变差,进来的是低质流量 | 新客占比上升,且各渠道内部转化率不变 | 分渠道看转化率普遍下降,说明是全局问题 | 渠道 × 新老客交叉表,看组内是否同降 | 0.5 人日 | 北辰优选的实际结果是:H1 的分层差异显著(安卓低端 38%、iOS 55%),回滚后 48 小时内恢复;H2 被反证(未用券用户同样下降);H3 被反证(分渠道普遍下降)。三个假设里一个成立、两个排除,这个结论比「我们认为是支付页问题」强得多,因为**排除本身就是信息**——它告诉后来的人不必再往那两个方向查。 5 Whys 是另一种常用工具,适合在锁定环节后继续往机理深处走。下面是 3 月的另一次复盘(与 9 月这次无关,用来说明方法),同样是新客支付转化率下降,看它如何从现象问到可控点。 | 层级 | 问题 | 回答 | 证据 | | --- | --- | --- | --- | | Why 1 | 为什么新客支付转化率下降? | 结算到支付这一步流失增加,从 68% 降到 54% | 漏斗分步转化率 | | Why 2 | 为什么这一步流失增加? | 支付页加载失败率从 0.9% 升到 5.4% | 前端错误日志按日聚合 | | Why 3 | 为什么失败率上升? | 3 月初上线新版支付页,接入了新的第三方 SDK | 发版记录与断点日期吻合 | | Why 4 | 为什么新 SDK 会导致失败? | 弱网与低端机型下请求超时,且没有做降级 | 分机型、分网络的成功率 | | Why 5 | 为什么上线前没发现? | 灰度只覆盖 iOS 与新机型,缺少低端安卓与弱网用例 | 灰度名单与测试用例清单 | 问到第五层,答案已经是一个可以改的动作:补灰度分层、补弱网用例、加超时降级。这就是 5 Whys 的价值——它把「技术问题」这种无法执行的结论,逼成「灰度策略缺了一类设备」这种可以排期的结论。 但 5 Whys 有个结构性缺陷:每一层只追一条线,很容易得到一个整洁但片面的叙事。更稳的做法是先用鱼骨图并行铺开可能原因,再对每条分支做 5 Whys。鱼骨图的六个分支可以按业务改写为:用户(需求、价格敏感)、系统(发版、第三方依赖、性能)、商品(缺货、涨价、评价)、流程(券规则、结算步骤、客服)、外部(竞争、季节、政策)、数据(口径、埋点、延迟)。铺开是为了不漏,追问是为了到底,两者顺序不能反。 ## 八、诊断报告:六段式结构与三条纪律 诊断做完了,还要让人相信。报告不需要长,但结构要固定,让读者知道每一段在回答什么。 **一、现象**:一句话说清什么指标、什么时间、变化多少。例:9 月 GMV 1150 万元,环比下降 8.0%(-100 万元)。 **二、范围**:说明影响面,哪些用户、渠道、地区、品类被波及,哪些没有。范围本身就是结论的一部分,「只影响安卓低端机新客」比「影响新客」信息量大一个量级。 **三、拆解**:给出拆解树和贡献度表,让读者能自己复算。至少包含一层加法或乘法拆解,以及一层维度拆解。 **四、证据**:每条证据标注来源、时间窗、样本量。证据要能支持结论,也要能排除替代解释——被排除的假设同样要写进来。 **五、结论**:区分三种状态。「已证实」(有实验或强证据)、「高度可能」(证据一致但无实验)、「待验证」(有方向但证据不足)。混在一起写,是诊断报告最常见的问题。 **六、待验证与行动**:下一步做什么、谁来做、多久能看到结果、如果结论错了会观察到什么。最后一条尤其重要,它让报告具备自我纠错能力。 三条纪律,值得贴在显示器边上。第一,**每个结论句后面要能指到一条证据**,指不到的句子删掉。第二,**不把猜测写成结论**,「可能是」「或许」要么升级成假设去验证,要么明确标为待验证,不要用模糊措辞蒙混。第三,**给出量级和不确定性**,「约 100 万元」「±15 万元」比「大幅下降」有用得多。 诊断性分析的天花板,是它只能处理「已经发生的事」,而且永远受限于观察数据。想在「为什么」上拿到更硬的证据,需要主动制造差异——这就是下一篇要讲的实验。而在那之前,先把口径、拆解、下钻、因果边界这四件事做扎实,已经能解决日常八成的「为什么跌了」。 ## 本篇要点回顾 1. 诊断的第一步是怀疑数据:口径、埋点、时区、退款、重复计算、延迟六类假信号,能凭空造出一个 8% 的下跌。 2. 加法拆解定位「哪一类」,北辰优选新客贡献了 100 万跌幅中的 80 万,问题立刻从全局收敛到新客。 3. 乘法拆解要看贡献度而非变化率:UV 涨 4% 带来 +50 万,转化率下滑吃掉 101.6 万,后者才是主因。 4. 下钻按「总体 → 维度 → 链路 → 用户 → 时间」推进,9 月 8 日的断点把排查范围从一个月压到一天。 5. 归因模型是分配规则不是因果测量,同一笔 300 元订单在五种模型下可以分出五个不同的「真相」,证明有效性仍要靠实验。 ## 延伸阅读 - **第 03 篇|描述性分析与指标体系**:本篇的所有拆解都建立在指标定义清楚的前提上,漏斗、留存、RFM 的分层口径在那篇里定义,读本篇前建议先确认口径一致。 - **第 05 篇|统计推断与 AB 实验**:本篇反复说「相关不等于因果」,那篇给出正面解法——随机分流、假设检验、置信区间,是把「高度可能」升级为「已证实」的工具。 - **第 02 篇|数据准备与 SQL 取数**:异常核查里的三条 SQL 只用了基础聚合,join 放大、时区归日、去重这些取数细节在那篇展开。 - **第 09 篇|行业实战:电商与 SaaS**:本篇的渠道 × 新老客 × 机型交叉,是电商诊断的标准动作,那篇会把增长、漏斗、复购的诊断路径串成完整流程。 - **第 11 篇|分析报告与沟通**:六段式结构如何变成一页纸、如何把「待验证」讲得不让老板焦虑,属于沟通问题,那篇专门处理。