SequenceMatcher: Python 字符串序列处理速效救心丸

博客围绕NER模型预测结果出现的问题展开。业务方反馈模型预测结果存在特殊字符、空格被吞的问题,原解决思路因字符编码和空格问题难以实现。最终借助Python原生difflib库,利用其比较序列对、找最长公共子序列的功能,快速优雅地解决了问题。

引言

最近工作偶尔会跟 NER 模型(命名实体识别)打交道,简单介绍一下背景,NER 模型的输出是一个结构化数据,比如:

// 万达广场沙县小吃
{
    "slot": "沙县小吃",
    "start": "4",
    "end": "8",
    "entity": "商铺"
}

在交付给业务方之前,需要使用 BIO 方案将原字符串序列转换成一个带命名实体标签的字符串序列:

万达广场沙县小吃
=>
万_O 达_O 广_O 场_O 沙_B-商铺 县_I-商铺 小_I-商铺 吃_I-商铺

如果事情到这里就结束了,那简直皆大欢喜,卷完下班。然而,在实践中,业务方们那儿反馈了两个问题,直接「被迫」加班。

问题一:模型预测的结果里,为啥会有 [UNK]_O 这样的字符?没法看好不啦…

一个业务方要的是一个古文领域的 NER 模型,不难想象,总是存在一部分生僻的汉字字符。熟悉 BERT 的同学都知道,无法识别的汉字字符,在数据预处理阶段,我们习惯上会直接拿一个特殊的 [UNK] 替代它。这也就意味着,模型预测结果,自然而然地存在如问题描述中所示的字符:[UNK]_O

问题二:原来的文本序列包含空格的,为啥预测的序列内,空格被吞了?这跟标注的序列一样又不一样,脑壳疼…

你可能会问,那如果数据集不是古文,而是常用的现代汉语数据集,那应该不会出现问题一了吧?当然,然而故事永远不会这么简单。另一个业务方反馈了问题二,经过一番排查,发现是模型在预测输入文本之前,会对待预测文本作分词处理,再以空格为分隔符重新合并成一个字符串,方便后续处理,比如:

重庆冰淇淋 红豆冰粉
=>
重庆 冰淇淋 红豆 冰粉

如此一来,空格就被吞掉了…不管是问题一还是问题二,如果只在乎被识别的命名实体,那其实无伤大雅。不过业务方的态度出奇得一致,纷纷表示这样不行,预测序列除开标签,必须与预测文本完全一致。

基本思路

看到问题一,我们很自然地想到了通过遍历的方式对两个序列进行比对,遇到同一位置不一致的字符(特指其中一个字符是 [UNK])时,替代即可。于是我们闭着眼睛,一气呵成:

def replace_unk(text: str, sequence: str) -> str:
    characters = [word for word in text]
    tokens, tags = (
        list(map(lambda item: item.split("_")[0], sequence.split())),
        list(map(lambda item: item.split("_")[1], sequence.split())), 
    )
    
    for i in range(len(characters)):
        if characters[i] == tokens[i]:
            continue
        tokens[i] = characters[i]

    retur
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值