2. 故障现象文本标准化与同义归并
为什么同一故障会被统计成多个簇
城轨车辆维修工单里的故障描述由不同岗位、不同班次的人员手写录入,同一物理现象常出现多种表述。例如牵引逆变器过流,可能被写成“牵引变流器过流保护”“逆变器OC”“VVVF过流跳闸”。如果直接按原始文本聚类,这些工单会被拆成多个独立簇,导致重复故障被漏判、重复率被低估。本案例的任务是建立一条可复用的文本标准化流水线:分词 → 同义词归并 → 标准编码,并用归并前后重复故障簇数量的变化来验证效果。
标准化流水线的结构
下图给出本案例的处理链:原始描述先经过领域词典分词,再经同义词表映射到标准词,最后按“部件码-现象码”规则生成标准编码。右侧对比了归并前后的簇数量变化,这是本案例的核心观察指标。
分词与同义词表的构建
分词质量取决于领域词典。城轨车辆故障文本中,部件名(牵引变流器、制动控制单元、车门控制器、受电弓)和现象词(过流、接地、跳闸、异响、漏风、卡滞)必须作为整体词条加入词典,否则会被切碎导致后续匹配失败。同义词表采用“标准词 ← 变体词列表”的结构,一个标准词可对应多个变体。
下面给出一个可直接运行的最小实现,使用 Python 标准库完成,不依赖第三方分词包,用词典最长匹配实现分词,用字典实现同义归并,用规则生成标准编码。
import re
# 1. 领域词典(部件词 + 现象词),按长度降序保证最长匹配
DOMAIN_WORDS = [
"牵引变流器", "制动控制单元", "车门控制器", "受电弓",
"过流", "过电流", "接地", "跳闸", "异响", "漏风", "卡滞", "保护", "动作",
"逆变器", "VVVF", "OC", "BCU", "DCU",
]
DOMAIN_WORDS.sort(key=len, reverse=True)
# 2. 同义词表:标准词 -> 变体集合
SYNONYMS = {
"牵引变流器": {"逆变器", "VVVF", "变流器"},
"过流": {"过电流", "OC"},
"保护": {"跳闸", "动作"},
"制动控制单元": {"BCU"},
"车门控制器": {"DCU"},
}
# 3. 标准编码规则:部件码 + 现象码
PART_CODE = {
"牵引变流器": "TC-01",
"制动控制单元": "BC-01",
"车门控制器": "DR-01",
"受电弓": "PN-01",
}
PHENOM_CODE = {
"过流": "OC-PROT",
"接地": "GND-FLT",
"异响": "NOISE",
"漏风": "AIR-LEAK",
"卡滞": "STUCK",
}
def tokenize(text):
"""基于领域词典的最长匹配分词"""
tokens, i = [], 0
while i < len(text):
matched = False
for w in DOMAIN_WORDS:
if text.startswith(w, i):
tokens.append(w)
i += len(w)
matched = True
break
if not matched:
i += 1 # 跳过非词典字符(标点、空格等)
return tokens
def normalize(tokens):
"""同义归并:变体词映射到标准词"""
variant_map = {}
for std, variants in SYNONYMS.items():
for v in variants:
variant_map[v] = std
return [variant_map.get(t, t) for t in tokens]
def encode(tokens):
"""生成标准编码:部件码-现象码"""
part = next((PART_CODE[t] for t in tokens if t in PART_CODE), None)
phenom = next((PHENOM_CODE[t] for t in tokens if t in PHENOM_CODE), None)
if part and phenom:
return f"{part}-{phenom}"
return None
# 4. 示例工单描述
records = [
"牵引变流器过流保护",
"逆变器OC跳闸",
"VVVF过流",
"变流器过电流动作",
"制动控制单元漏风",
"BCU漏风",
]
# 5. 处理并统计簇数量
before, after = set(), set()
for r in records:
toks = tokenize(r)
norm = normalize(toks)
code = encode(norm)
before.add(r) # 原始文本作为簇标识
if code:
after.add(code) # 标准编码作为簇标识
print(f"{r:20s} -> {toks} -> {norm} -> {code}")
print(f"\n归并前簇数: {len(before)}")
print(f"归并后簇数: {len(after)}")
运行上述代码,输出中前四条描述都会归并到 TC-01-OC-PROT,后两条归并到 BC-01-AIR-LEAK。归并前簇数为 6,归并后簇数为 2,说明同义归并有效聚合了重复故障。
结果判读与常见问题
- 簇数下降但未到预期:说明同义词表有遗漏,需补充变体词。例如“过流保护”与“过流跳闸”若未把“跳闸”映射到“保护”,编码会缺失现象码而返回 None。
- 簇数异常骤降:可能是过度归并,例如把“接地”和“过流”错误映射到同一标准词,导致不同故障被合并。应逐条核对映射表。
- 编码为 None 的记录:说明分词后缺少部件词或现象词,需检查词典覆盖度,这类记录应单独列出人工复核,不能直接丢弃。
同义词表应随工单数据迭代维护。建议每次新增故障类型时,同步补充领域词典和同义词变体,并回归测试归并前后簇数量变化,确保标准化规则不退化。
标准编码规则中部件码与现象码必须来自受控词表,不允许自由文本拼接,否则编码本身会再次产生同义变体,使归并失效。