一个质控部门手里可能有三年的抽检记录:几万行,每行是一次检测,写着产品、供应商、产地、采样日期、检测项目和结果。下一轮只有预算做几百次检测,该抽谁?只凭经验,容易反复抽同一批熟悉的对象;只按“不合格次数多”排序,又会把偶然事件当成规律。让模型参与的目的,是把这份历史整理成一个可排序的依据,先检最值得检的。首页哪一批更值得检查那篇讲的是这件事的概貌,这里把数据怎样一步步变成优先级拆开来看。
从记录到特征
模型不能直接读一行行流水记录,它需要每个对象在“此刻”的一组数字。下面这张表列出了常见字段怎样被转换(记录内容均为示意,实际字段取决于手里有什么数据)。
| 字段 | 记录里的样子(示意) | 转成的特征 | 容易踩的坑 |
|---|---|---|---|
| 产品 | 菠菜,属叶菜类 | 类别编码,保留细类与大类两级 | 细类样本太少时,要回退到大类的整体水平 |
| 供应商 | 供应商 S-014 | 近 90 天检测次数、不合格次数、平滑后的不合格率 | 只有两三次记录时,比例极不稳定 |
| 地区 | 产地所在省份 | 地区编码,以及同地区同季节的历史结果 | 划分过细,每个地区只剩几个样本 |
| 季节 | 采样日期 3 月 12 日 | 周次或月份,可结合当周气温与降水 | 只用“季度”太粗,同一季度内变化很大 |
| 历史结果 | 检测项目与结论 | 按项目分列的不合格记录、最近一次不合格距今多久 | 要区分“没检这个项目”与“检了合格” |
| 距上次抽检天数 | 上次采样在 45 天前 | 天数,可取对数 | 很久没检过的对象本身就是盲区 |
这张表里有两处值得多说。一是不合格率要平滑:某供应商只检过两次、一次不合格,比例是 50%,这个数字几乎没有信息量,通常需要向同类别或同地区的整体水平“收缩”,样本越少,越靠近整体水平。二是“距上次抽检天数”看上去与污染无关,其实它是在给模型一个补偿:太久没被检查的对象,我们对它的了解已经过时。
冷启动,以及探索与利用
新供应商没有任何历史,这是冷启动。合理的做法是让它先继承所在品类、地区与季节的整体风险,再随着检测结果逐步更新。记录为空只说明没检过,不说明没有问题。
只按模型给的高分去抽检,会带来另一个更隐蔽的问题。高优先级对象被反复抽检,自然发现更多问题,历史里的“不合格”越来越集中在它们身上;低优先级对象几乎没被抽过,模型永远不知道它们真实情况如何。这就是抽样偏差:越常被抽检的对象,越容易“发现问题”。它对应着探索与利用的取舍,利用是把资源投向已知的高风险,探索则是保留一部分预算做随机抽检,去看盲区里有什么。这个比例要看资源和风险承受度,比如保留一成到两成(仅为举例,不是推荐值)。随机抽到的样本还有第二个用途:它比较接近无偏,可以用来检验模型的排序是否真的比随机抽检更有效。
结果回写,形成闭环
每一轮抽检完成以后,结果必须写回历史:检测项目、方法、结果、是否复测,以及这次抽样是“按风险选的”还是“随机选的”。最后这个标记很关键,缺了它,下一轮训练时就分不清哪些样本受了选择偏差的影响。
- 抽检历史
- 特征整理
- 风险模型
- 下一轮优先级
- 执行抽检与检测
- 结果回写
图里那个并联的“随机探索抽样”,就是上面说的保留部分随机抽检。它不追求效率,追求的是让历史数据不至于越来越偏。
输出的是优先级,不是合格判定
模型输出的是“这一批应当排在第几位”,或者一个经过校准的风险概率,用来决定先检谁、检哪些项目。概率校准(Calibration)的意思是,分数要尽量与实际发生的比例对得上:如果一批分数都在 0.3 上下的对象,事后统计实际问题率与 0.3 相去甚远,这个分数就只能当排序用,不能当概率读。它不能给一批食品下“合格”的结论:合格与否依据的是法定检验方法和适用法规的现行版本,由具备资质的实验室出具结果。也因为如此,排序有没有用,可以用具体的方式来检验:在同样的抽检预算下,按模型排序抽检是否比随机抽检发现了更多真实问题,这要用保留的随机抽检数据来对比。
纵横国际食品安全栏目接下来讨论的问题是,为什么这份排序不能只靠历史不合格次数来算,环境、天气和供应链又是怎样进入模型的。