数据质量:4 层去重 + 黑名单机制------宁可漏杀,不可错杀
这是《AI数字员工系统设计与企业自动化实战》日志连载第 34 篇
作者:老高FDE-AI实战前沿
深度聚焦:企业AI落地实战、AI-Workforce、AI数字员工实战、企业Agent组织设计、企业Agent架构搭建
文章目录
- [数据质量:4 层去重 + 黑名单机制------宁可漏杀,不可错杀](#数据质量:4 层去重 + 黑名单机制——宁可漏杀,不可错杀)
- 前言
- [一、4 层去重:按确定性从高到低](#一、4 层去重:按确定性从高到低)
- [二、黑名单词长分级:2 字词的教训](#二、黑名单词长分级:2 字词的教训)
- 三、数据质量三原则
- 四、"宁可漏杀,不可错杀"
- 五、三个容易踩的坑
-
- [坑 1:用模糊相似度去重](#坑 1:用模糊相似度去重)
- [坑 2:黑名单放短词](#坑 2:黑名单放短词)
- [坑 3:静默丢弃,误伤了都不知道](#坑 3:静默丢弃,误伤了都不知道)
- 六、本章小结
- 结语
前言
先讲一个我们自己踩过、代价不小的坑。
早期我们做企业采集,建了个黑名单,把"不该采的企业"过滤掉。
有一天,我们往黑名单里加了一个词:"科技"。
本意是过滤掉一批不想碰的企业。
结果呢?
所有名字里带"科技"的公司,全被误伤排除了------"XX 科技有限公司""YY 科技集团"......一大批正经的目标企业,一夜之间进不了池子。
更糟的是,因为黑名单是"静默过滤",我们过了好几天才发现:池子里该入的企业没入,排查了半天,才定位到是那两个字惹的祸。
这件事让我们记住了一句话:
数据质量的第一原则,不是"过滤得干净",是"别误伤"。
今天讲数据质量的两大件:4 层去重 和 黑名单机制。
(还记得 Day 23 讲过"垃圾数据进去,垃圾结论出来"吗?那是"标准"的问题;今天讲的是"重复和误伤"的问题,是数据质量的另一半。)
一、4 层去重:按确定性从高到低
数据池里最烦人的,是同一家企业被采进来好几遍。
怎么去重?答案是按"确定性"从高到低,分四层:
#mermaid-svg-DAhUTOKudpGNXaOD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DAhUTOKudpGNXaOD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DAhUTOKudpGNXaOD .error-icon{fill:#552222;}#mermaid-svg-DAhUTOKudpGNXaOD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DAhUTOKudpGNXaOD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DAhUTOKudpGNXaOD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DAhUTOKudpGNXaOD .marker.cross{stroke:#333333;}#mermaid-svg-DAhUTOKudpGNXaOD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DAhUTOKudpGNXaOD p{margin:0;}#mermaid-svg-DAhUTOKudpGNXaOD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DAhUTOKudpGNXaOD .cluster-label text{fill:#333;}#mermaid-svg-DAhUTOKudpGNXaOD .cluster-label span{color:#333;}#mermaid-svg-DAhUTOKudpGNXaOD .cluster-label span p{background-color:transparent;}#mermaid-svg-DAhUTOKudpGNXaOD .label text,#mermaid-svg-DAhUTOKudpGNXaOD span{fill:#333;color:#333;}#mermaid-svg-DAhUTOKudpGNXaOD .node rect,#mermaid-svg-DAhUTOKudpGNXaOD .node circle,#mermaid-svg-DAhUTOKudpGNXaOD .node ellipse,#mermaid-svg-DAhUTOKudpGNXaOD .node polygon,#mermaid-svg-DAhUTOKudpGNXaOD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DAhUTOKudpGNXaOD .rough-node .label text,#mermaid-svg-DAhUTOKudpGNXaOD .node .label text,#mermaid-svg-DAhUTOKudpGNXaOD .image-shape .label,#mermaid-svg-DAhUTOKudpGNXaOD .icon-shape .label{text-anchor:middle;}#mermaid-svg-DAhUTOKudpGNXaOD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DAhUTOKudpGNXaOD .rough-node .label,#mermaid-svg-DAhUTOKudpGNXaOD .node .label,#mermaid-svg-DAhUTOKudpGNXaOD .image-shape .label,#mermaid-svg-DAhUTOKudpGNXaOD .icon-shape .label{text-align:center;}#mermaid-svg-DAhUTOKudpGNXaOD .node.clickable{cursor:pointer;}#mermaid-svg-DAhUTOKudpGNXaOD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DAhUTOKudpGNXaOD .arrowheadPath{fill:#333333;}#mermaid-svg-DAhUTOKudpGNXaOD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DAhUTOKudpGNXaOD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DAhUTOKudpGNXaOD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DAhUTOKudpGNXaOD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DAhUTOKudpGNXaOD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DAhUTOKudpGNXaOD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DAhUTOKudpGNXaOD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DAhUTOKudpGNXaOD .cluster text{fill:#333;}#mermaid-svg-DAhUTOKudpGNXaOD .cluster span{color:#333;}#mermaid-svg-DAhUTOKudpGNXaOD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DAhUTOKudpGNXaOD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DAhUTOKudpGNXaOD rect.text{fill:none;stroke-width:0;}#mermaid-svg-DAhUTOKudpGNXaOD .icon-shape,#mermaid-svg-DAhUTOKudpGNXaOD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DAhUTOKudpGNXaOD .icon-shape p,#mermaid-svg-DAhUTOKudpGNXaOD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DAhUTOKudpGNXaOD .icon-shape .label rect,#mermaid-svg-DAhUTOKudpGNXaOD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DAhUTOKudpGNXaOD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DAhUTOKudpGNXaOD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DAhUTOKudpGNXaOD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 信用代码
精确匹配,最可靠
② 归一化名称
名称标准化后匹配
③ 别名
人工维护的别名表
④ 新建
都不匹配,判定为新企业
| 层 | 依据 | 可靠性 |
|---|---|---|
| ① 信用代码 | 法律唯一标识(统一社会信用代码) | 最高 |
| ② 归一化名称 | 名称标准化后比对 | 高 |
| ③ 别名 | 人工维护"曾用名→现用名"表 | 中 |
| ④ 新建 | 都不匹配,判定为新企业 | 兜底 |
核心逻辑(伪代码):
python
def dedup(company):
# ① 信用代码:最可靠
if company.credit_code:
existing = find_by_credit_code(company.credit_code)
if existing:
return "duplicate", existing
# ② 归一化名称
norm_name = normalize(company.name)
existing = find_by_norm_name(norm_name)
if existing:
return "duplicate", existing
# ③ 别名
alias = find_alias(company.name)
if alias:
return "duplicate", alias
# ④ 新建
return "new", None
一句话记住:能用信用代码,绝不用名称猜。
信用代码是法律层面的唯一标识,最可靠;名称会变、会重名,只能当第二选择。
拿一条真实数据走一遍"四层去重"。一条新采的数据进来:
名称:智慧物流(集团)有限公司
信用代码:91XXXXXXXXXXXXXX
它进池前,要过四关:
- ① 信用代码 :拿
91XXXXXXXXXXXXXX一查,池子里已经有了(历史采过一次,当时叫"智慧物流有限公司")→ 判定重复,不新建,只更新; - ②③④:连走都不用走,第一层就拦住了。
关键就在这:四层是"层层降级",不是"层层都走"。 第一层(信用代码)命中,直接判定重复,后面不查了。
反过来,如果这家企业没有信用代码,第一层跳过,走第二层"归一化名称"------把"(集团)"去掉、统一后缀,再比对。这才轮到名称。
能拦在哪一层,取决于数据的"确定性"有多高。确定性越高,越早拦住,越不会误判。
二、黑名单词长分级:2 字词的教训
回到开头的坑。黑名单为什么误伤?
因为词太短。
"科技"两个字,太常见了,一匹配就误伤一片。
解法是词长分级:
| 词长 | 处理 |
|---|---|
| ≥4 字 | 可直接精确匹配(如"骗子公司") |
| 3 字 | 需结合上下文判断 |
| 2 字 | 高危,禁用或需极严格额外条件(太常见,必误伤) |
python
def check_blacklist(company_name):
for word in BLACKLIST:
if len(word) >= 4: # ≥4字:精确匹配
if word in company_name:
return "blacklist"
elif len(word) == 3: # 3字:需上下文
if word in company_name and is_suspicious(company_name):
return "blacklist"
# 2字词:禁用,太常见,必误伤
return "ok"
关键:2 字词不进黑名单(除非有极严格的条件),防止"科技""物流""网络"这类常见词误伤一片。
三、数据质量三原则
去重和黑名单背后,是三条更底层的原则:
| 原则 | 一句话 | 例子 |
|---|---|---|
| 确定性优先 | 能用确定性规则,不用概率规则 | 用信用代码,不用模糊相似度 |
| 防边界 | 规则要防"误伤" | 黑名单词长分级 |
| 过滤前置 | 过滤放"入池前",不是"入池后" | 去重在写入前做,不让脏数据进池 |
这三条里,最重要的是"确定性优先"。
数据质量出问题,往往是"用了不确定的规则"------比如用"相似度 80% 算重复",这种概率规则覆盖全,但会误判。
确定性规则(信用代码)虽然覆盖不全,但可靠;概率规则覆盖全,但会误伤。优先确定性,是数据质量的定海神针。
四、"宁可漏杀,不可错杀"
把去重和黑名单想清楚,会发现它们都是"过滤"。
而过滤,有两种错误:
| 错误 | 含义 | 后果 |
|---|---|---|
| 漏杀 | 该过滤的没过滤 | 轻,可后补(再跑一遍去重) |
| 错杀 | 不该过滤的被过滤 | 重,数据永久丢失 |
所以原则只有一句:
宁可漏杀,不可错杀。
重复的数据,漏了可以再补一次去重;误伤的数据,一旦排除,就永久丢了,你甚至不知道丢了。
先保证不错杀,再逐步减少漏杀。 这是两害相权取其轻。
(开头的"科技"坑,就是"错杀"------而且因为静默过滤,连丢了都不知道。后来我们改成:误伤的进"待人工复核"队列,人能看见,这才把"错杀"变"可发现"。)
五、三个容易踩的坑
坑 1:用模糊相似度去重
"名称相似度 80% 以上就算重复。"
结果:把"智慧物流科技"和"智慧物流信息"两家不同的公司判成了同一家。
破解:确定性优先------有信用代码,绝不用相似度猜。
坑 2:黑名单放短词
"加个'科技'过滤一下。"
结果:所有带"科技"的正常企业全被误伤。
破解:词长分级,2 字词禁用,3 字加条件,4 字才精确匹配。
坑 3:静默丢弃,误伤了都不知道
"不符合规则的就直接扔掉。"
结果:误伤的企业被静默排除,你连"丢了数据"都不知道。
破解:误伤的进"待人工复核"队列,错了能看见、能修正。
六、本章小结
今天讲的是数据质量的两大件。
4 层去重:信用代码 → 归一化名称 → 别名 → 新建,按确定性降级。
黑名单词长分级:2 字高危禁用,3 字加条件,4 字精确匹配。
三原则:确定性优先、防边界、过滤前置。
记住 3 个要点:
- 能用信用代码,绝不用名称猜------确定性优先是定海神针
- 2 字词不进黑名单------短词必误伤
- 宁可漏杀,不可错杀------误伤不可挽回,漏杀可后补
最后送大家一句话:
宁可漏杀,不可错杀。
数据质量的第一要义,是别把好东西误伤掉。
结语
这一篇解决了"数据别脏、别误伤"。
到这里,第五周(落地实战)的内容就讲完了。下一篇,照例做一周一次的复盘。
《Day 35:周复盘------5 个真实项目案例分享》
这一周讲的全是"落地",评论区也攒了不少真实的踩坑故事。下一篇我挑 5 个最有代表性的,摊开讲------别人的坑,是你的路。
💬 互动话题:你们公司有没有"黑名单误伤"或者"同一家客户被算成好几遍"的经历?踩过的最坑的一个数据质量事故是什么?评论区聊聊,我帮你看看该用哪一层去重堵上。
本文来自《AI数字员工系统设计与企业自动化实战》系列探索。
内容围绕:企业AI落地实战、AI-Workforce、AI数字员工实战、企业Agent组织设计、企业Agent架构搭建。
持续更新!