本人在使用pipeline方式融合一些自定义词语后,发现当自定义词典语料过多时,即语料复杂,出现分词结果变差。例如:正要打牌九。当自定义词典有"要"、“打牌"等词,如果先通过自定义词典去分词,就会分出"要”、"打牌"等词,再通过模型进行分词,分出来的就是【“正”,“要”、“打牌”、“九”】,这样就没有达到预期的效果。请问类似这样的问题,我应该怎么处理呢。希望大家能提供一些更好的建议。谢谢!
1 Like
这里应该是还存在一个bug,Trie类的parse_longest函数。例:“密码设置"进行分词,假设自定义词库含有"密码”、"码"两个词,parse_longest会分出[“密码”, “码”, “设置”],这不是预期的效果,应该是[“密码”, “设置”]。
自定义的词典里应该也有“牌九”这个词语吧 没有的话可以手动加一下
当自定义词典有"牌九"这个词时,效果是【“正”,“要”、“打牌”、“牌九”】,这不是预期的。正确应该是【“正要”、“打”、“牌九”】。
你这是全搜索模式吧 相当于用ac算法扫描了一次“正要打牌九”中含有的词典词汇
看看哪里能切换一个模式的
我用jieba来做说明的话 cut_all开关打开的话就会出现你的这个结果
hanlp没有类似的开关,其本身是更灵活,需要自己去实现。
已经修复:
好的,谢谢何博士。但是我还是有个疑问,例如,自定义词库只有"码"这一个字,没有"密码"这一词,结果就是【“密”, “码”, “设置”】了,之前你们的例子在自定义词库与模型结合使用是行不通的。你觉得呢?
不太明白你的意思,请仿照这个例子把你的问题复现出来
- - coding:utf-8 - -
Author: hankcs
Date: 2019-12-28 21:25
from hanlp.common.trie import Trie
import hanlp
tokenizer = hanlp.load(‘PKU_NAME_MERGED_SIX_MONTHS_CONVSEG’)
text = ‘密码设置’
trie = Trie()
trie.update({‘码’})
def split_sents(text: str, trie: Trie):
words = trie.parse_longest(text)
sents = []
pre_start = 0
offsets = []
for word, value, start, end in words:
if pre_start != start:
sents.append(text[pre_start: start])
offsets.append(pre_start)
pre_start = end
if pre_start != len(text):
sents.append(text[pre_start:])
offsets.append(pre_start)
return sents, offsets, words
def merge_parts(parts, offsets, words):
items = [(i, p) for (i, p) in zip(offsets, parts)]
items += [(start, [word]) for (word, value, start, end) in words]
# In case you need the tag, use the following line instead
# items += [(start, [(word, value)]) for (word, value, start, end) in words]
return [each for x in sorted(items) for each in x[1]]
tokenizer = hanlp.pipeline() \
.append(split_sents, output_key=(‘parts’, ‘offsets’, ‘words’), trie=trie) \
.append(tokenizer, input_key=‘parts’, output_key=‘tokens’) \
.append(merge_parts, input_key=(‘tokens’, ‘offsets’, ‘words’), output_key=‘merged’)
print(tokenizer(text)) # [“密”, “码”, “设置”]
好的,明白了,谢谢何博士的回答!
不错不错。支持pytorch不?