2. 故障现象文本标准化与同义归并

为什么同一故障会被统计成多个簇

城轨车辆维修工单里的故障描述由不同岗位、不同班次的人员手写录入,同一物理现象常出现多种表述。例如牵引逆变器过流,可能被写成“牵引变流器过流保护”“逆变器OC”“VVVF过流跳闸”。如果直接按原始文本聚类,这些工单会被拆成多个独立簇,导致重复故障被漏判、重复率被低估。本案例的任务是建立一条可复用的文本标准化流水线:分词 → 同义词归并 → 标准编码,并用归并前后重复故障簇数量的变化来验证效果。

标准化流水线的结构

下图给出本案例的处理链:原始描述先经过领域词典分词,再经同义词表映射到标准词,最后按“部件码-现象码”规则生成标准编码。右侧对比了归并前后的簇数量变化,这是本案例的核心观察指标。

故障描述文本标准化处理链 原始描述(示例) 牵引变流器过流保护 逆变器OC跳闸 VVVF过流 变流器过电流动作 (同现象,4种写法) 领域词典分词 牵引变流器 / 过流 / 保护 逆变器 / OC / 跳闸 VVVF / 过流 变流器 / 过电流 / 动作 词典含部件名、现象词 同义词归并 逆变器 → 牵引变流器 VVVF → 牵引变流器 OC / 过电流 → 过流 跳闸 / 动作 → 保护 映射表驱动 标准编码 部件码:TC-01 现象码:OC-PROT 组合码:TC-01-OC-PROT 4条工单 → 同一编码 编码规则:部件-现象 归并前后重复故障簇数量对比(示例数据) 归并前 4 个独立簇 同现象被拆散 归并 归并后 1 个合并簇 4条工单归入同簇 判读要点 • 簇数量下降说明同义归并生效,重复故障被正确聚合 • 若归并后簇数不降,检查同义词表是否覆盖该现象 • 若簇数异常骤降,检查是否过度归并(不同现象被合并)

分词与同义词表的构建

分词质量取决于领域词典。城轨车辆故障文本中,部件名(牵引变流器、制动控制单元、车门控制器、受电弓)和现象词(过流、接地、跳闸、异响、漏风、卡滞)必须作为整体词条加入词典,否则会被切碎导致后续匹配失败。同义词表采用“标准词 ← 变体词列表”的结构,一个标准词可对应多个变体。

下面给出一个可直接运行的最小实现,使用 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 的记录:说明分词后缺少部件词或现象词,需检查词典覆盖度,这类记录应单独列出人工复核,不能直接丢弃。
同义词表应随工单数据迭代维护。建议每次新增故障类型时,同步补充领域词典和同义词变体,并回归测试归并前后簇数量变化,确保标准化规则不退化。
标准编码规则中部件码与现象码必须来自受控词表,不允许自由文本拼接,否则编码本身会再次产生同义变体,使归并失效。