# 换个汇总方式，同一批数据为什么给出不同的数

同一批数据换个分组键就得到不同的数，根源是两件事：一行代表什么，以及哪些列能加、哪些列只能分组

> 数据粒度 · 指标口径 · 分组汇总 · 约 8 分钟 · 09 月 22 日

## 本篇要点

1. 数据粒度就是“这张表的一行代表什么”，用一句话写下来，它决定了后面哪些汇总做得通、哪些数能对上。
2. 一张表的列分成两种角色：维度列用来分组、筛选、打标签，指标列是被汇总的数；数字不一定是指标，订单号、年份这类只能分组的列属于维度。
3. 分组汇总的过程就是选几个维度列当分组键，把行分进桶，再在桶里合并指标。
4. 可加指标（件数、金额）不管怎么分组总量都不变，变的只是它在各个桶里的分布；找原因靠的正是这个分布的差别。
5. 数数要看粒度：明细表的行数是订单行的数量，订单数要不重复计数，两者差多少取决于每单买几类商品。
6. 不可加指标（单价、平均、比率、转化率）会随分组改变数值，因为平均里藏着“除以多少”这个隐含选择，按行平均和按件平均可以是两个不同的数。
7. 处理比率和平均的规矩是回到底层重算，用分子除以分母，而不是对已经算好的比率再求和或再平均。
8. 当各切片的权重差异足够大、切片变量本身又强烈影响结果时，整体数字甚至会和每个分组里的结论相反，机制仍然是加权。

---

上一篇讲到 A 渠道跌 40%、B 渠道涨 50%，合起来只跌 4% 时，说的是“整体数字会把相反方向的变化抵消”。这一篇往下再钻一层，问一个更基础的问题：为什么把同一批数据按不同方式加起来，会得到不同的数？有时候连方向都不一样。

答案藏在两件事里：这张表的一行代表什么，以及每一列在汇总时扮演什么角色。这两件事没弄清楚，取回来的数看着对，其实答的是另一个问题。

## 先问一句话：这张表的一行代表什么

拿起一张表，先别急着看有哪些列，先问：一行是什么？

假设你拿到下面这张销售明细表，这是电商后台导出时最常见的形状：

| 订单号 | 品类 | 件数 | 单价（元） |
| --- | --- | --- | --- |
| A1001 | 电脑 | 1 | 6000 |
| A1001 | 配件 | 2 | 100 |
| A1002 | 配件 | 3 | 50 |
| A1003 | 电脑 | 1 | 4000 |

这张表的一行是“某个订单里的某一个品类”。用一句话写下来就是：一行 = 一个订单行。

这句声明决定了后面几乎所有事。订单 A1001 因为买了两类商品，占了两行。所以这张表里数一下行数得到 4，但订单只有 3 个。行数和订单数是两个数，它们差多少，取决于每单平均买几类商品，不是一个固定比例。

这就是**数据粒度**（grain，也叫颗粒度）：一行代表什么。粒度不是“越细越好”的技术选项，它是一条信息边界。细粒度的表可以往上汇总：订单行能合成订单，也能合成品类、合成月。反过来做不到：如果导出时已经是“每月每品类一行”，那笔 6000 元的电脑卖给谁、和哪件配件一起买的，这些细节就永远找不回来了 [1]。

## 表里的列分成两种角色

再看列。这张表的四列，做事的方式完全不同。

**订单号、品类**：它们的作用是把你手里的行分进不同的桶，或者筛掉一部分行。你不会把“电脑”和“配件”加起来，也不会把订单号加起来。这类列是**维度列**（dimension），用来分组、筛选、打标签。

**件数、单价**：它们是被汇总的对象，是**指标列**（measure）。分组之后，桶里这些数要合并成一个数。

分这两种列有个很实用的判断法：在报表里，这一列你打算求和、求平均，还是打算放进筛选器、坐标轴、图例？前一种是指标，后一种是维度 [2]。

这里有个最容易踩的坑：**数字不一定是指标**。订单号是数字，年份是数字，商品编码也常常是数字，但它们都不能加。“2024 加 2025”没有意义，不是因为它们不是数字，而是因为它们描述的是“这一行属于哪一类”，属于维度。

## 汇总的时候发生了什么

所有“换个方式汇总”，本质上都是同一件事：选一组维度列当分组键，把行分进桶，再在每个桶里合并指标列。

按品类分组，得到两个桶（收入需要现算，等于件数乘单价）：

| 品类 | 收入（元） | 件数 |
| --- | --- | --- |
| 电脑 | 6000 + 4000 = 10000 | 2 |
| 配件 | 200 + 150 = 350 | 5 |
| 合计 | 10350 | 7 |

按订单分组，得到三个桶：

| 订单号 | 收入（元） |
| --- | --- |
| A1001 | 6200 |
| A1002 | 150 |
| A1003 | 4000 |
| 合计 | 10350 |

同一批数据，同一个总量 10350，但每一块的数字完全不同。这不是哪一次算错了，而是你在问两个不同的问题：一个问“哪类商品贡献多少”，一个问“哪些订单值钱”。

这里有个必须看清楚的性质：**可加的量，不管怎么分组，总量都不变，变的只是它在各个桶里的分布。** 件数和收入都是可加的，所以按品类分也好、按订单分也好、按星期几分也好，加起来永远是 7 件、10350 元。会变的只有分布。

所以“换个汇总方式数字变了”，对可加指标来说，从来不是总量变了，而是你换了一个看这个总量的切法。找原因靠的就是这个：总量给不出的答案，往往能从分布的差别里读出来。

顺便说，数数也要看粒度。上面那张明细表，数行数得到 4，那是订单行的数量；要知道有几个订单，得数不重复的订单号，得到 3。这两个数都成立，只是回答的问题不同。写口径时如果把“订单数”写成“行数”，数字会随着用户一次买几类商品而变，看着像业务在波动，其实是购物篮的构成在变。

## 换成平均单价，账就不平了

上面说的都是可加量。麻烦出在另一类指标上。

同样是那四行数据，问一句“平均单价多少”，两种都叫平均单价，答案却差了一千多块。

**第一种：把单价列按行平均。**
$$\frac{6000+100+50+4000}{4}=\frac{10150}{4}=2537.5 \text{ 元}$$

**第二种：总收入除以总件数。**
$$\frac{10350}{7}\approx 1478.6 \text{ 元}$$

两个数都“算对了”，但含义不同。第一种回答的是“平均每个订单行的单价是多少”，它把 6000 元的电脑和 50 元一件的配件摆在同一地位，各算一行；第二种回答的是“平均每一件商品卖了多少钱”，那行 50 元的配件因为买了 3 件，权重是笔记本那行的 3 倍。

差在哪？**单价是不可加的。** 你把四行的单价加起来，得到一个没有意义的 10150 元；你把两个品类的平均单价再取平均，得到的也不是整体的平均单价。原因是：平均值里已经藏了一次除法，它自带一个“除以多少”的隐含选择——按行除还是按件除，是两件事。

这个毛病在每个分组里都存在。看配件那一组：两行的单价是 100 和 50，按行平均是 $(100+50)/2=75$ 元；按件平均是 $350\div5=70$ 元。便宜那款卖了 3 件，按行平均就把它压成和贵的同等的分量，于是算出 75，比真实的每件均价高了 5 元。而电脑那一组两种算法都是 5000 元，因为每行正好一件——你看不出问题，纯属巧合。

所以处理平均、比率、转化率这类指标，有一条硬规矩：**不要在汇总层对这些数再求和或再平均，回到底层，用分子除以分母重新算。** 要平均单价，就用总收入除以总件数；要复购率，就用复购人数除以有机会复购的人数 [2][4]。分子和分母都是可加的，放在哪里都算得对；比率本身不是。

这也解释了上一篇那个格局：整体跌 4%，是因为 A 渠道的 36 万和 B 渠道的 60 万按各自体量加权之后合在一起。整体数字本质上是各切片的加权平均，权重一变，合出来的数就变。

## 同一个机制，能把方向整个翻过来

如果各切片的权重差得足够大，而且那个切片变量本身强烈影响结果，整体数字甚至能和每一个分组里的结论相反。

经典的例子是两种肾结石治疗方案。治疗 A 在小于 2 厘米的结石上成功率 93%（81/87），在大结石上是 73%（192/263）；治疗 B 分别是 87%（234/270）和 69%（55/80）。每个分组里都是 A 更好。但两组加起来，A 是 273/350 = 78%，B 是 289/350 ≈ 83%，B 反而更好 [3]。

原因还是那个加权：医生把更难治的大结石更多分给了 A（263 例对 80 例），A 的总成功率就被这批难病例拖下去了。合起来那个 78% 里，绝大部分权重压在低成功率的大结石上；B 的 83% 里，权重压在容易治的小结石上。两边的权重结构完全不同，比的其实不再是同一种病人。

这也说明拆解本身为什么有价值：它不只是把表切得更细，而是让“权重结构不同”这件事露出来。

## 落到手上：三个动作

**一、先写粒度。** 拿到一张表，用一句话写下“一行代表什么”。写不出来，就先别做分组汇总，这时候算出来的任何数都是碰运气 [1]。

**二、分清哪些列能加。** 要汇总的数归一类，用来分组和筛选的归另一类。特别注意那些长得像数字但不能加的列。

**三、遇到比率就退回去重算。** 看到平均、比率、百分比、转化率，先找它的分子和分母，用明细重算，不要对已经算好的比率再平均。

这三条之外，还有两个问题值得在动手前问一遍：我要数的这个数是数行、数订单还是数客户，换个口径会不会变？这个指标是能加的，还是会在粗粒度表和细粒度表上给出不同的值？

## 收尾

回到开头那个问题。“换个汇总方式数字就变了”，不是数据有问题，是你在问不同的问题：分组键换了，桶就换了；桶换了，桶里装了多少行、多少件也就换了。

可加的量——件数、金额——不管怎么分组，总量守恒，变的只是分布，而分布正是你找原因的地方。不可加的量——平均单价、比率、转化率——会随着分组改变数值，因为你换分组的同时，也悄悄换了它的权重。

上一篇写指标口径时要求说清“分子数什么、分母是什么”，那时其实埋了一个前提：你得知道分母里的每一行代表什么。这一篇补上的就是这个前提。粒度定下来，维度和指标分清楚，口径才站得住；否则同一句“这个月销量下滑”，两个人取回来的数可以完全不一样，而且两边都没算错。

## 术语表

- 数据粒度（grain）：这张表的一行代表什么，比如“一行 = 一个订单行”，用一句话写下来。
- 维度列（dimension）：用来分组、筛选、打标签的列，通常是文字或类别；数值型但只用来分类的列也算维度。
- 指标列（measure）：分组之后要在每个桶里合并的数，比如件数、金额。
- 可加指标：不管按哪个维度分组，总量都不变的指标，如件数、收入。
- 不可加指标：里面已经做过一次除法、不能直接相加或再平均的指标，如单价、比率、转化率；要用分子除以分母重算。
- 分组汇总：选一组维度列当分组键，把行分进桶，再在桶里合并指标列。

## 来源

1. [Data Panda 数据词典：Granularity (grain) — 粒度是“一行代表什么”，细粒度可向上汇总，粗粒度丢失的细节无法恢复](https://datapanda.eu/en/dictionary/granularity-grain)
2. [Fact or Dimension: A Guide to Reading a Data Model — 用一句话声明粒度，区分可加、半可加与不可加指标](https://medium.com/@anchitgupt/fact-or-dimension-the-all-in-one-guide-to-reading-a-data-model-and-nailing-the-interview-4d580d8fb0af)
3. [Wikipedia: Simpson's paradox — 肾结石两种治疗方案的分组与合计成功率数据](https://en.wikipedia.org/wiki/Simpson%27s_paradox)
4. [Difference Between Fact Table and Dimension Table — 混用不同粒度会造成重复计数，比率类数值不宜直接存放和相加](https://thelinuxcode.com/difference-between-fact-table-and-dimension-table-a-practical-guide-for-reliable-analytics/)

---

原文：https://pangzhengboyin.com/articles/data-grain-dimensions-and-measures-b8378dd2

> **庞征博引** · 想学的，慢慢都会
>
> 庞征博引是把想学的东西写成连载的 AI 学习工具。说出想学什么，它会先了解你的基础，再把主题写成一篇篇 5–10 分钟能读完的文章；边读边问，接下来学什么跟着你走。这篇就是这样写出来的。
>
> 开始你自己的连载 → https://pangzhengboyin.com
