把八家店按店址切成两格,每一格里降价都更好——方向和总体相反。 那个同时在两边起作用、又不在研究链条上的变量,叫混杂因素。它有三条腿,缺一条都只是巧合。 这一篇讲怎么认出它、怎么用拆分管住它,以及为什么拆分永远管不干净。
上一篇排除了问卷这条路,回到门店表。这一篇是第 2 章的核心:混杂因素。 第 9 章(直方图)会从「看形状」的角度再碰一次这个问题, 第 11 章(误差)会把它变成「分割数据」。
一、切开就看见了
按店址把八家店分成两格,每格里再按降不降价分——四组:
| 店址 | 降价 | 家数 | 变化 |
|---|---|---|---|
| 社区 | 降 | 3 | −15.0% |
| 社区 | 没降 | 1 | −18.0% |
| 商圈 | 降 | 1 | −2.0% |
| 商圈 | 没降 | 3 | −5.0% |
两格里方向一致,都是降价好 3 个百分点。可合起来,降价组更差 4.9 个百分点。
二、混杂因素的三条腿
跟结果有关:店址影响销售额。社区店整体跌 18%,商圈店只跌 5%。 跟分组有关:降不降价和店址相关——社区店更倾向于降价(生意差,想自救)。 不在研究链条上:店址不是降价造成的,它先于降价存在。
三条全占才是混杂因素。少一条,它只是「另一个变量」,不会把结论掰弯。
三、为什么会把方向掰反
因为组间差异 = 处理效果 + 分组差异。你不把分组差异扣掉,就会把它记在处理效果头上。 降价组背负了「社区店」这个身份,而社区店本身在暴跌。于是降价背了黑锅。 这就是辛普森悖论在实验场景里的样子:每一格都朝一个方向,合起来朝反方向。
四、拆分能管住它,但管不干净
按店址拆开,混杂就被固定住了——同类店里店址相同,差异只能来自降价。 可店址不是唯一的混杂因素。店长能力、装修新旧、门口有没有地铁口,每一个都同时影响两边。 你能想到几个就拆几个,永远拆不完。想不到的那些,数据里根本没有字段。
五、一个实用判断
看到「总体方向和每一格都相反」,第一反应就该是「有个变量在分组里不均」。 找它的办法不是算,是问:这两组在收数据之前就不一样的地方有哪些。 答案通常在业务常识里,不在统计软件里。
六、动手 Demo:混杂因素:藏在店址里的那只手
同一张表,切一刀,四行。看组内方向与总体方向怎样分道扬镳。 最后两行是这次的结论:混杂能拆掉一部分,拆不完。
stores = [('S01', 'community', True, 120.0), ('S02', 'community', True, 110.0),
('S03', 'community', True, 90.0), ('S04', 'downtown', True, 80.0),
('S05', 'downtown', False, 130.0), ('S06', 'downtown', False, 100.0),
('S07', 'downtown', False, 85.0), ('S08', 'community', False, 75.0)]
rate = {('community', True): -0.15, ('community', False): -0.18,
('downtown', True): -0.02, ('downtown', False): -0.05}
now = [s[3] * (1 + rate[(s[1], s[2])]) for s in stores]
for site in ('community', 'downtown'):
for cut in (True, False):
idx = [i for i, s in enumerate(stores) if s[1] == site and s[2] == cut]
a = sum(stores[i][3] for i in idx)
b = sum(now[i] for i in idx)
print('%-10s %-5s %d 家 %+.1f%%'
% (site, 'cut' if cut else 'keep', len(idx), (b / a - 1) * 100))
for cut in (True, False):
idx = [i for i, s in enumerate(stores) if s[2] == cut]
a = sum(stores[i][3] for i in idx)
b = sum(now[i] for i in idx)
print('总体 %-5s %d 家 %+.1f%%'
% ('cut' if cut else 'keep', len(idx), (b / a - 1) * 100))
实跑输出:
--------------------------------------------------------------------
混杂因素:藏在店址里的那只手
--------------------------------------------------------------------
① 把数据按店址切开
--------------------------------------------------------------------
| 店址 | 降价 | 门店数 | 销售额变化 |
|---|---|---:|---:|
| 社区 | 降 | 3 | -15.0% |
| 社区 | 没降 | 1 | -18.0% |
| 商圈 | 降 | 1 | -2.0% |
| 商圈 | 没降 | 3 | -5.0% |
② 每一格里,降价都更好
--------------------------------------------------------------------
社区店:降价 −15.0%,没降 −18.0%,差 3 个百分点。
商圈店:降价 −2.0%,没降 −5.0%,也差 3 个百分点。
两格里方向一致:降价让销售额多撑住了 3 个点。
! 可合起来,降价组反而更差 4.9 个百分点——这就是混杂因素的力量。
③ 混杂因素的三条腿
--------------------------------------------------------------------
| 条件 | 在这里是什么 |
|---|---|
| **跟结果有关** | 店址影响销售额:社区店整体跌 18%,商圈店只跌 5% |
| **跟分组有关** | 降价店四家里三家在社区 |
| **不在研究链条上** | 店址不是降价造成的,是先于降价存在的 |
三条全占,就是一个合格的混杂因素。少一条都只是巧合。
④ 拆分能管理它,但管不干净
--------------------------------------------------------------------
按店址拆开,你能看到「同类店里降价更好」。
可店址不是唯一的混杂因素:店长能力、装修新旧、门口有没有地铁口,
哪一个都同时影响「降不降价」和「卖得好不好」。
你能想到几个就拆几个,但永远拆不完——因为你想不到的那些,数据里没有。
四行里两行是 −15 对 −18,两行是 −2 对 −5:组内差都是 3 个点,方向一致。 最后两行却翻过来了。这就是汇总的代价——它把结构信息平均掉了。
30 秒实验
- 把 S04(商圈降价)改成社区降价,四格会变成什么样?总体方向还翻吗?
- 再切一刀「店长是否新上任」,自己造一组数,看组内差会不会变。
- 想一想:如果某个混杂因素是「门店面积」,你能在现有的表里发现它吗?
常见误区
- 只管拆分不管样本量:拆完每组剩一家,结论的误差比效应还大。
- 把相关当混杂:只有同时影响「分组」和「结果」的变量才是混杂,只影响结果的不算。
- 以为拆完就干净:拆分只能处理你想到并记录下来的变量。
- 在混杂没排除前就报结论:这一步省下的时间,后面要用双倍去解释「为什么和实际相反」。
自测三问(点开对答案)
1. 混杂因素的三条腿是什么? —— 跟结果有关、跟分组有关、不在研究链条上(不是被研究因素造成的)。 2. 为什么拆分之后方向会反过来? —— 因为组间差异等于处理效果加分组差异。拆开后分组差异被固定住,剩下的才是处理效果。 3. 拆分为什么管不干净? —— 只能拆你已经想到并且记下来的变量。没想到的、没记成字段的,仍然在暗处起作用。拆分确实救回来一点,但刚要下结论,又冒出第二个混杂因素:降价的那几家店,去年都换了店长。
- ☐ (本篇完,下一篇 2.5 情况更糟了)