跳转至

P7-1.2 基线与首次比较

Section ID: P7-1.2 Version: v2026.08.01

首次比较要先固定基线、候选规则、比较单位和指标,然后把结果分成事实、解释与下一问题。这样基线不只是一个数字,而是下一次调查的共同参照。

把数值放在基线上阅读

仅写“平均访问量为 150.7”或“某日最好”不能说明当前结果是否偏离平常范围。项目记录应说明:使用了什么基线、当前值是什么、差异是什么,以及哪一项值得先检查。

项目 记录的作用
基线 给当前值提供比较轴和时间范围
当前值 说明刚刚计算的观测值
差异 指出当前值相对基线的变化
事实 只陈述代码或记录直接支持的内容
解释 写出仍需验证的可能性
下一问题 指定最小的后续检查

基线先于结论出现。没有基线,“高”或“低”只是形容词;有了基线,才能说某个渠道相对自身近期记录发生了多大变化。

不要把事实、解释和行动混在一句话里

类型 广告渠道示例
事实 广告渠道的近期转化率低于同渠道的基线。
解释 变化可能与投放、落地页、追踪或流量构成有关。
下一问题 先检查错误类型、活动设置和渠道-日期记录。

“错误导致注册下降”是因果结论,而当前日志只显示错误率上升与转化率下降同时出现。更安全的写法是:“两项变化同时出现,因此需要进一步检查它们是否有关。”

flowchart TD
  A["最近渠道-日期记录"]
  B["与同渠道基线比较\n转化率和错误率"]
  C["转化率优先规则\n筛选候选"]
  D["错误率优先规则\n筛选候选"]
  E["两个规则的共同候选"]
  F["分开记录\n事实、解释、下一问题"]
  A --> B
  B --> C --> E
  B --> D --> E --> F

两种候选规则

本节继续使用 p7-1-traffic-log.zh.csv。比较单位是最近区间中的一个渠道-日期行;每行与同渠道的基线汇总比例比较。

审查规则 保留候选的条件
转化率优先 转化率至少下降 3.5 个百分点,错误率至少上升 0.9 个百分点
错误率优先 转化率至少下降 2.5 个百分点,错误率至少上升 1.2 个百分点

百分点不是百分比增长率。-0.035 表示转化率比基线低 3.5 个百分点;0.009 表示错误率高 0.9 个百分点。这些阈值是安排审查顺序的规则,不证明原因或统计显著性。

import csv
from collections import defaultdict
from datetime import datetime
from pathlib import Path

rules = [
    {"name": "转化率优先", "conversion_drop_max": -0.035, "error_rise_min": 0.009},
    {"name": "错误率优先", "conversion_drop_max": -0.025, "error_rise_min": 0.012},
]
rows = list(csv.DictReader(Path("docs/assets/part-07/chapter-01/p7-1-traffic-log.zh.csv").open(encoding="utf-8")))
for row in rows:
    row["date"] = datetime.strptime(row["date"], "%Y-%m-%d").date()
    row["visitors"] = int(row["visitors"])
    row["signups"] = int(row["signups"])
    row["errors"] = int(row["errors"])

cutoff = datetime.strptime("2026-06-08", "%Y-%m-%d").date()
baseline_rows = [row for row in rows if row["date"] < cutoff]
recent_rows = [row for row in rows if row["date"] >= cutoff]
totals = defaultdict(lambda: {"visitors": 0, "signups": 0, "errors": 0})
for row in baseline_rows:
    for field in ("visitors", "signups", "errors"):
        totals[row["channel"]][field] += row[field]
for total in totals.values():
    total["conversion"] = total["signups"] / total["visitors"]
    total["error"] = total["errors"] / total["visitors"]

candidates = {rule["name"]: [] for rule in rules}
for row in recent_rows:
    base = totals[row["channel"]]
    conversion_delta = row["signups"] / row["visitors"] - base["conversion"]
    error_delta = row["errors"] / row["visitors"] - base["error"]
    for rule in rules:
        if conversion_delta <= rule["conversion_drop_max"] and error_delta >= rule["error_rise_min"]:
            candidates[rule["name"]].append((row["date"].isoformat(), row["channel"], round(conversion_delta, 4), round(error_delta, 4)))
print(candidates)
print("common candidates =", sorted(set(candidates[rules[0]["name"]]) & set(candidates[rules[1]["name"]])))

代码先按渠道汇总基线,再逐行比较最近记录。它保留每个候选的日期、渠道、转化率差异和错误率差异,以便审查者回到原始日志,而不是只看候选数量。

共同候选为什么优先

两个规则不是同一个条件的宽松和严格版本。一个更重视转化率下降,另一个更重视错误率上升。因而同时通过两个规则的行,表示两个指标在各自阈值下都值得查看。

候选状态 应如何阅读
只出现在转化率优先规则 转化率变化更值得先检查;错误率证据较弱或未到阈值。
只出现在错误率优先规则 错误率变化更值得先检查;转化率证据较弱或未到阈值。
同时出现在两种规则 两项信号共同指向该渠道-日期;作为优先审查候选。
不在任何规则中 这不等于正常或无风险;只是未满足本次规则。

共同候选是审查优先级,不是根因结论。仍应检查访问量、注册数、错误类型、浏览器、部署记录和活动上下文。

相对基线的转化率与错误率变化;红色区域表示共同候选区域

改变规则时应记录什么

团队可能改变阈值、切分日期或假设的渠道情景。每次改变都必须保留原规则和新规则,以免把规则变化误读成数据变化。

改变项 可能改变的内容 必须固定或记录的内容
切分日期 基线和最近区间中的行 新旧日期范围
转化率阈值 转化率优先候选 错误率阈值和数据版本
错误率阈值 错误率优先候选 转化率阈值和数据版本
某渠道假设情景 特定渠道最近行 原始 CSV 不变、调整规则单独记录

一次只改变一个设定,才能解释候选为何进入或离开列表。

将候选写成下一问题

1
2
3
4
5
基线:广告渠道在切分日期之前的汇总转化率和错误率。
当前值:某个最近广告渠道-日期行。
事实:该行满足转化率和错误率的共同候选规则。
解释:广告渠道的变化可能与运营异常或投放变化有关。
下一问题:先检查该日期的错误类型、活动设置和追踪记录。

这个格式避免把“满足规则”写成“已经知道原因”。它也让后来的人知道下一次检查从哪里开始。

学习检查

  1. 能否说明为什么基线必须先于解释出现?
  2. 能否把一个句子拆成事实、解释和下一问题?
  3. 能否解释两个规则的共同候选为何比单规则候选优先?
  4. 能否把 -0.0350.009 读成百分点差异?
  5. 能否说明阈值规则不能证明什么?

读取本次运行的候选列表

在默认切分日期下,转化率优先规则选出 5 个广告渠道-日期候选;错误率优先规则选出 3 个。共同候选是 06-11、06-12、06-14 的广告记录。这个结果首先说明候选规则确实改变了优先级,而不是所有低转化率行都自动进入同一列表。

规则 候选日期 应先保留的事实
转化率优先 06-10、06-11、06-12、06-13、06-14 每行都出现较大的转化率下降,并达到较低的错误率上升门槛。
错误率优先 06-11、06-12、06-14 这些行的错误率上升达到更高门槛。
两者共同 06-11、06-12、06-14 两项差异在各自规则下均需要审查。

共同列表不意味着三天是同一个事件。它只说明在当前指标、阈值和切分日期下,这三行都值得优先回查。应分别检查每一天的错误类型、流量来源和部署记录。

将百分点差异变成可读记录

日期 渠道 转化率差异 错误率差异 安全的事实句
06-11 ads -0.0388 0.0134 广告渠道相对自身基线的转化率下降 3.88 个百分点,错误率上升 1.34 个百分点。
06-12 ads -0.0378 0.0129 两个比例都达到本次共同候选规则。
06-14 ads -0.0385 0.0126 该日期应与同渠道其他最近行一起审查。

不要将 -0.0388 写成“下降 3.88%”而不说明是百分点。百分点比较的是两个比例之间的直接差;百分比增长还需要指定分母,容易把解释带到另一个问题。

为每个候选写五栏记录

栏位 06-11 广告候选的示例
基线 切分日期之前广告渠道的汇总转化率与错误率。
当前值 06-11 广告渠道-日期记录的两个比例。
事实 转化率和错误率差异都满足本次规则。
解释 运营异常、投放变化或追踪变化都有可能;尚未确认。
下一问题 错误是否集中于某浏览器、页面或部署后时间段?

这五栏能防止项目记录从一行数值跳到一个根因。基线和当前值告诉读者比较的输入;事实描述规则结果;解释保持条件性;下一问题把调查变成可执行动作。

解释句的边界

不安全的句子 为什么不安全 更稳妥的句子
广告活动失败了。 日志没有验证活动质量或因果。 广告渠道的近期记录偏离自身基线,需要检查活动设置。
错误造成了注册下降。 同时出现不代表原因。 错误率上升与注册相关指标下降同时出现,需要检查关联。
06-11 是最坏的一天。 没有定义“最坏”的指标和比较范围。 06-11 满足两项审查规则,在当前记录中优先回查。
共同候选已经证明问题。 阈值只筛选候选。 共同候选提供更强的审查优先级。

条件性表达不是削弱结论,而是让后续实验可以推翻或支持它。项目文档应让读者清楚知道哪些部分已经由代码确认,哪些仍需外部证据。

当规则或情景改变时重新比较

原始 CSV 不应为了试验而被覆盖。若想模拟广告渠道注册数减少或错误数增加,应在内存中记录一个明确的调整,并与默认情景分开输出。

1
2
3
4
5
默认情景:不调整最近行。
情景变量:目标渠道、注册数调整、错误数调整。
比较单位:仍为最近的渠道-日期行。
保持不变:数据文件、切分日期、两个规则和基线计算方式。
记录结果:每个规则的候选、共同候选、进入和离开列表的行。
变更 会回答的问题 不会回答的问题
减少最近广告注册数 更低转化率会使哪些行进入候选? 真实活动是否会导致相同变化。
增加最近广告错误数 错误率门槛如何影响候选? 错误的业务原因。
改变切分日期 基线窗口如何改变比较? 哪个窗口天然正确。
改变阈值 审查资源会优先分配给哪些行? 任何候选的根因。

情景实验的目的不是制造最醒目的图表,而是理解判断规则对哪些输入敏感。把情景变量与实际观测数据分开,能避免读者误把模拟结果当成日志事实。

共同候选之后的调查顺序

  1. 回到候选日期的原始访问量、注册数和错误数。
  2. 按错误类型、浏览器、页面或地区拆分,确认增长是否集中。
  3. 对照当天的活动、落地页、追踪脚本和部署记录。
  4. 与未进入共同列表的广告日期比较,寻找差异而不是只收集支持证据。
  5. 写出一个最小验证动作,例如检查某次部署后错误类别是否增加。
  6. 只有在证据支持时,才扩大到数据收集、修复或后续模型实验。

这个顺序从最接近记录的证据开始。它避免把一个候选直接升级为大范围项目改动。

反例也要保留

没有进入共同候选的行不是无用数据。它们可以帮助检查规则是否过于宽松、某种变化是否只发生在广告渠道,或一个拟议解释是否也应预测其他日期的相同行为。

保留的反例 可以检查什么
转化率下降但错误率未达到门槛的广告日 两个信号是否真的需要同时出现?
错误率上升但转化率稳定的广告日 错误是否必然影响注册?
同日的自然或搜索渠道 是否存在全站或日期共同变化?
稳定的广告日 某个活动或部署前后的差异。

良好的审查记录既保留问题行,也保留比较行。否则“解释”只能看到被规则选中的证据。

项目回顾示例

在当前切分日期和规则下,广告渠道的 06-11、06-12、06-14 同时满足转化率下降和错误率上升的审查条件。该事实把这些行列为优先候选,但不证明广告活动、页面或错误本身导致了注册变化。下一步将保留相同基线,检查每个日期的错误类别、访问量构成和部署记录,并与未进入共同候选的日期比较。

这段回顾包含比较条件、观察事实、解释限制和下一行动。若其中任一项改变,应写成新的运行记录而不是修改旧结论。

常见问题

问题 回答
是否只看共同候选? 共同候选优先,但单规则候选和稳定行仍是比较证据。
阈值由谁决定? 由项目风险、审查资源和目标决定;必须记录,而不是假装自然给定。
能否用更复杂模型替代规则? 不能跳过输入、基线和错误证据。模型比较也需要同样的记录结构。
为什么不直接把最高错误率行当作答案? 最高值没有说明相对基线、样本量或与转化变化的关系。

提交前检查

检查项 自问问题
基线 是否写明同渠道、日期范围和汇总方法?
规则 是否分别记录两种候选条件?
单位 是否确认一行是渠道-日期,而不是总体日期?
百分点 是否把比例差异按百分点解释?
共同候选 是否说明它是优先级而不是根因?
回顾 是否分开写出事实、解释和下一问题?
反例 是否保留未进入共同候选的比较行?

如果这些项都能回答,首次比较就不仅是一张候选表,而是一份可复查的下一步调查计划。

为什么这种比较方式在实际工作中重要

运营团队通常同时看到大量指标、告警和报表。若没有统一的基线和候选规则,讨论很容易变成“我觉得这个数字很奇怪”。把比较写成同一格式后,不同角色可以围绕同一证据协作。

角色 首先需要的记录 能据此做的事
数据分析人员 基线、当前值、差异、数据范围 复现计算并检查分母或过滤条件。
工程人员 错误率候选、日期、错误类型 对照部署、日志和服务状态。
运营人员 渠道候选、活动时间、流量构成 检查投放、页面或受众变化。
审查者 事实、解释、下一问题 发现因果断言或缺失的反例。

同一模板并不要求所有人有同一种解释。它要求解释先连接到可回查的行、规则和比较窗口。

从候选表到任务列表

候选证据 可以创建的最小任务 完成时应留下什么
共同候选中的错误率上升 列出该日期的错误类别 类别计数、总访问量和查询条件。
广告渠道单独下降 检查活动和落地页变更 时间戳、变更说明和未变更的对照日期。
特定浏览器错误集中 拆分浏览器和版本 各组分母、错误率和样本量。
阈值边缘的候选 比较相邻日期 为什么保留或不保留的规则说明。

任务不是“修复广告”。任务应该描述要增加哪一份证据,以及该证据会如何改变下一判断。

用两个规则做小型敏感性检查

两个规则让学习者看到结论如何依赖判断设定。可以在不改变 CSV 的情况下分别改变一个门槛,比较候选集合。

1
2
3
4
5
运行 A:转化率优先规则与默认切分日期。
运行 B:错误率优先规则与默认切分日期。
比较:共同候选、仅 A 候选、仅 B 候选。
保持固定:数据文件、渠道定义、基线计算和最近区间。
记录:每一行的百分点差异,不只记录候选数量。
比较结果 可以说什么 不能说什么
候选集合相同 在这两个规则下优先级一致。 阈值选择不重要。
候选集合不同 优先级依赖指标权重和门槛。 某一规则一定正确。
共同集合很小 少数行同时满足两类信号。 其他行没有风险。
共同集合为空 当前规则没有重叠候选。 数据没有值得调查的问题。

敏感性检查让规则本身成为项目记录的一部分。这样阈值变动不会在以后看起来像数据突然改变。

进一步的练习

  1. 将转化率优先规则的下降门槛改为 -0.025,比较新增的候选行。
  2. 将错误率优先规则的上升门槛改为 0.009,说明它与第一条规则有什么不同。
  3. 将切分日期推迟一天,写出哪些基线行和最近行发生移动。
  4. 只为广告渠道设置一个模拟的错误数调整,并记录这是情景而非观测。
  5. 选择一个只在单规则中出现的行,为它写五栏记录。
  6. 为一个未被选中的广告日期写反例说明:它缺少哪一个信号?
  7. 将共同候选和单规则候选分别交给“工程检查”和“运营检查”,说明所需证据为何不同。

每个练习都应保留原始运行输出。不要只留下修改后的最有趣结果,否则比较失去基线。

将结果转成下一次实验问题

候选表的最后一列不应是“结论”。它应该是能在下一轮得到新证据的问题。

已知事实 可检验问题 需要的新证据
广告共同候选的错误率上升 错误是否来自同一页面或浏览器? 错误类别和客户端拆分。
转化率下降集中于广告 流量来源或落地页是否变化? 活动、UTM、页面版本和来源构成。
其他渠道未显示相同模式 是否存在广告特有变更? 渠道配置和时间线。
某日期接近阈值 是否为短期噪声? 相邻日期和更长窗口的比较。

问题需要能被证据回答。比如“为什么广告不好”太宽;“06-11 广告错误是否集中在某个部署后的页面路径”则可以由日志查询回答。

模板:事实、解释、下一问题

比较范围:
基线定义:
当前渠道-日期:
转化率差异(百分点):
错误率差异(百分点):
规则结果:
事实:
可能解释:
未验证的替代解释:
下一问题:
最小检查:
保留的反例:

模板中的“未验证的替代解释”很重要。它提醒作者不要只寻找支持第一种想法的证据。例如,广告错误率上升可能与页面有关,也可能与监控规则或流量构成变化有关。

完成标准

首次比较完成时,读者应能让另一人重建:使用了哪份数据、何时切分、每个规则如何筛选、哪些行共同出现,以及下一步要检查什么。若只能重建最后一句解释,项目记录还不够。

最低产物 验证方法
规则表 能重新计算每个候选条件。
基线与当前值 能追溯到渠道-日期原始行。
候选集合 能区分共同、单规则和未选中行。
回顾段落 明确标注事实、解释限制和下一问题。
下一任务 能说明要读取或检查的新证据。

这套结构会在后续 Section 中反复使用:先建立可比较的基线,再保留错误或候选的证据,最后设计一个有限的下一步。

最后自查

在发布比较前,重新运行代码而不是手工编辑候选列表。 确认日期和渠道名称仍能在 CSV 中找到。 确认所有百分点差异都有相同的基线定义。 确认情景调整没有写回原始数据文件。 确认共同候选被称为审查优先级,而不是根因。 确认每个解释后面都有可执行的下一问题。 确认一个反例或稳定行仍在记录中。 确认读者可以区分默认运行和模拟运行。 确认阈值的来源和用途被写明。 确认没有把规则结果写成统计检验结果。 确认输出中的计数和比例能够回到同一输入行。 确认下一 Section 能使用这份记录继续分析。

规则的使用边界

候选规则用于安排有限的审查时间。 它们不替代异常检测模型、统计检验或因果分析。 规则改变时,应将旧候选列表保留在运行记录中。 若数据单位或时间范围改变,先重新定义基线再比较。 每个候选都需要原始计数和上下文作为后续证据。 不要只因某行进入列表就开始广泛修改系统。 先用下一问题收集能区分解释的最小证据。 让复查结果决定是否扩大调查范围。

来源与参考

本节的数据和示例为本书创建的练习材料。