文本根据词典进行纠错
输入一段可能带有错误信息的文字, 通过词典来检测其中可能错误的词。
例如:有句子如下:中央人民政府驻澳门特别行政区联络办公室1日在机关大楼设灵堂
有词典如下:中国人民,中央人民,澳门,西门
检测时,根据词典可以得出句子中的中央人民可能为中国人民,澳门可能为西门,并返回结果
处理逻辑如下:
- 首先对词典进行逐字打码,例如中国人民处理成:*国人民,中*人民,中国*民,中国人*,并返回一个index_list记录对应的位置和打码的位置(后面才可以根据这个index_list找到候选词)。
- 接着对句子进行N-gram,比如检测第二个字央时,设置n为4(一般都处理为4),处理成:中央,中央人,中央人民,央人,央人民,央人民政,并对央打码,处理成:中*,中*人,中*人民,*人,*人民,*人民政
- 最后与上述处理完的词典进行对比,如果找到相同的比如:词典里面的 中*人民 与 检测央时返回的N-gram里面的 中*人民相同,便根据index_list找到词典中的中国人民,由此可得,央字的候选词为国。如下:{‘correction’: ‘国’, ‘index’: 1, ‘candidate’: [‘中国人民’], ‘original’: ‘央’}
实现代码如下:
- 对词典进行处理:
def get_new_dict(dict):
'''
将词典逐字打码
:param dict:
:return: 新词典以及对应的index
'''
new_dict = []
index_list = []
for j in range(len(dict)):
for i in range(len(dict[j])):
if i < len(dict[j]):
new_dic = dict[j][:i] + '*' + dict[j][i+1:]
else:
new_dic = dict[j][:i] + '*'
new_dict.append(new_dic)
index_list.append((j,i))
return new_dict,index_list
#测试:
dicts = ['中国人民','中央人民','澳门','西门']
new_dict,index_list = get_new_dict(dicts)
print(new_dict)
print("**********************")
print(index_list)
输出:
index_list的元组第一个值表示词典的索引位置,第二个值表示对应这个词打码位置的索引
- 对句子进行N-gram
def get_ngram(content,loc,n):
'''
切分Ngram.函数为根据索引位置切分,如果想切分整个content,只需要加一个循环使loc从0到len(conten)-1
:param content: 原文
:param loc: 想要检测的字的索引位置
:param n: 切分长度
:return: ngram
'''
i_min = loc-n+1 if loc-n+1 >= 0 else 0
i_max = loc+1
j_min = loc+1
j_max = loc+1+n if loc+1+n < len(content) else loc+1+1
ngram_list = []
for i in range(i_min,i_max):
for j in range(j_min,j_max):
if j-i > 4 or j - i < 2:
continue
ngram_list.append(content[i:j].replace(content[loc],'*'))
return ngram_list
#测试
content = '中央人民政府驻澳门特别行政区联络办公室1日在机关大楼设灵堂'
loc = 1
ngram_list = get_ngram(content,loc,n=4)
print(ngram_list)
输出:
- 最后进行词典与N-gram的比对并返回相应结果:
def get_result(ngram_list,new_dict,index_list,loc,original,dicts):
'''
获取结果
:param ngram_list: 原文分割后的Ngram
:param new_dict: 打码处理后的字典
:param index_list: 处理后的字典对应的索引位置
:param loc: 检测字的索引位置
:param original: 检测的字
:param dicts: 原始词典
:return:
'''
candidate = []
error_dic = {}
for word in ngram_list:
if word in new_dict:
indexs = [i for (i, v) in enumerate(new_dict) if v == word]
for index in indexs:
index = index_list[index]
correction = dicts[index[0]][index[1]]
if original == correction:
continue
candidate.append(dicts[index[0]])
error_dic['correction'] = correction
error_dic['index'] = loc
error_dic['candidate'] = candidate
error_dic['original'] = original
return error_dic
#测试
original = content[loc]
error_dic = get_result(ngram_list,new_dict,index_list,loc,original,dicts)
print(error_dic)
输出:
{‘correction’: ‘国’, ‘index’: 1, ‘candidate’: [‘中国人民’], ‘original’: ‘央’}
完整代码如下:
def get_ngram(content,loc,n):
'''
切分Ngram.函数为根据索引位置切分,如果想切分整个content,只需要加一个循环使loc从0到len(conten)-1
:param content: 原文
:param loc: 想要检测的字的索引位置
:param n: 切分长度
:return: ngram
'''
i_min = loc-n+1 if loc-n+1 >= 0 else 0
i_max = loc+1
j_min = loc+1
j_max = loc+1+n if loc+1+n < len(content) else loc+1+1
ngram_list = []
for i in range(i_min,i_max):
for j in range(j_min,j_max):
if j-i > 4 or j - i < 2:
continue
ngram_list.append(content[i:j].replace(content[loc],'*'))
return ngram_list
def get_new_dict(dict):
'''
将词典逐字打码
:param dict:
:return: 新词典以及对应的index
'''
new_dict = []
index_list = []
for j in range(len(dict)):
for i in range(len(dict[j])):
if i < len(dict[j]):
new_dic = dict[j][:i] + '*' + dict[j][i+1:]
else:
new_dic = dict[j][:i] + '*'
new_dict.append(new_dic)
index_list.append((j,i))
return new_dict,index_list
def get_result(ngram_list,new_dict,index_list,loc,original,dicts):
'''
获取结果
:param ngram_list: 原文分割后的Ngram
:param new_dict: 打码处理后的字典
:param index_list: 处理后的字典对应的索引位置
:param loc: 检测字的索引位置
:param original: 检测的字
:param dicts: 原始词典
:return:
'''
candidate = []
error_dic = {}
for word in ngram_list:
if word in new_dict:
indexs = [i for (i, v) in enumerate(new_dict) if v == word]
for index in indexs:
index = index_list[index]
correction = dicts[index[0]][index[1]]
if original == correction:
continue
candidate.append(dicts[index[0]])
error_dic['correction'] = correction
error_dic['index'] = loc
error_dic['candidate'] = candidate
error_dic['original'] = original
return error_dic
#测试
#测试
dicts = ['中国人民','中央人民','澳门','西门']
content = '中央人民政府驻澳门特别行政区联络办公室1日在机关大楼设灵堂'
loc = 7
original = content[loc]
ngram_list = get_ngram(content,loc,n=4)
new_dict,index_list = get_new_dict(dicts)
error_dic = get_result(ngram_list,new_dict,index_list,loc,original,dicts)
print(error_dic)
'''
输出:
{'correction': '西', 'index': 7, 'candidate': ['西门'], 'original': '澳'}
'''
Macbert是什么?
原始 BERT 模型的缺点之一是预训练和微调阶段任务不一致,pretrain 有 [mask] 字符,而 finetune 没有。
MacBERT 用目标单词的相似单词,替代被 mask 的字符,减轻了预训练和微调阶段之间的差距。
输入一句话,给其中的字打上“mask”标记,来预测“mask”标记的地方原本是哪个字。
input: 欲把西[mask]比西子,淡[mask]浓抹总相宜
output: 欲把西[湖]比西子,淡[妆]浓抹总相宜