中文文本纠错 算例实现(有算例完整代码)
生活随笔
收集整理的這篇文章主要介紹了
中文文本纠错 算例实现(有算例完整代码)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
概述
文本糾錯又稱為拼寫錯誤或者拼寫檢查,由于純文本往往來源于手打或者OCR識別,很可能存在一些錯誤,因此此技術也是一大關鍵的文本預處理過程,一般存在兩大糾錯類型。
1拼寫錯誤
第一種是Non-word拼寫錯誤,表示此詞匯本身在字典中不存在,比如把“要求”誤寫為“藥求”,
2.少字多字
中文文本糾錯比較難,不多說。上思路
方法有很多,本文講解基于拼音
語言:python3.7
思路:
格式:第一列正確字詞,第二列 詞頻 ,第三列 詞性
本文只用詞和詞頻。考慮詞性太難啦對于特定行業的任務,可能需要在添加一些字詞進數據庫.txt。哪些字詞需要添加呀,一般是語音轉換容易錯的詞。
方法見鏈接:用100行python代碼發現語音識別文本錯誤詞,并將結果和正確詞一一對應
2.得有一個文檔txt,供編輯距離函數操作的。命名 編輯距離.txt
如下圖
3.加載 數據庫.txt 和 編輯距離.txt
4.輸入一個錯誤單詞(句子分詞得到的單詞,或者單獨一個錯誤單詞),計算編輯距離,生成編輯距離詞集。
編輯距離需要比對 數據庫.txt 的單詞,計算距離
然后對錯誤單詞進行刪除字,增加字,修改字,替換字。增加刪除替換哪些字呀,肯定得從 編輯距離.txt 文檔里選取字插入或替換到錯誤單詞里。 最后生成編輯距離詞集
5.生成的編輯距離詞集 肯定含有一些錯誤單詞,找出同時在編輯距離詞集和數據庫.txt 的單詞 ,即為我們候選正確詞集
6.對候選正確詞進行分級。首先 pinyin.get得到錯誤詞的拼音
然后遍歷 候選正確詞集的單詞,求取得拼音。
我們根據候選詞的拼音對其重要性進行排序
如果候選詞的拼音與錯誤詞完全匹配,則將候選詞放入一級數組
#如果候選詞的第一個詞的拼音與錯誤詞的第一個詞匹配,我們將其按二級數組。否則我們把候選短語放入三級數組.
7.找到正確單詞,如果一級數組存在, 得到 的正確字詞是在 數據庫.txt 中的。 考慮到得到的詞可能有多個,前文提到數據庫.txt 第一列是詞,第二列是詞頻 。我們應該返回一級數組中 詞在數據庫.txt 中詞頻最大的那個單詞
如果一級數組不存在,二級數組存在,,返回詞頻最大的那個單詞
否則:返回三級數組詞頻最大的那個單詞。
算例:
代碼:
1導入包 和標點符號
2讀取 數據庫.txt
只讀取第一列和第二列 ,最后生成字典。
#得到的是各單詞詞頻,如:{‘老師上課’: ‘3’, ‘老師傅’: ‘62’, ‘老師宿儒’: ‘老師上課’: ‘3’, ‘老師傅’: ‘62’, }
3.讀取編輯距離.txt
import pinyin#載入編輯距離的單詞列表 #cn_words_dict 用于編輯距離的,從里面選擇字來菜如或者替換目標詞 def load_cn_words_dict( file_path ):cn_words_dict = ""with open(file_path, "r",encoding='utf-8') as f:for word in f:cn_words_dict += word.strip()#去除首尾空格return cn_words_dict cn_words_dict = load_cn_words_dict("cn_dict.txt")#導入單字4. 計算錯誤單詞與數據庫.txt里的單詞的編輯距離
#函數計算與中文短語的距離 #cn_words_dict 用于編輯距離的,從里面選擇字來菜如或者替換目標詞 def edits1(phrase, cn_words_dict):"`所有的編輯都是一個編輯遠離'短語."#phrase = phrase.decode("utf-8")splits = [(phrase[:i], phrase[i:]) for i in range(len(phrase) + 1)]#將單詞前后分開deletes = [L + R[1:] for L, R in splits if R]#刪除transposes = [L + R[1] + R[0] + R[2:] for L, R in splits if len(R)>1]#轉換replaces = [L + c + R[1:] for L, R in splits if R for c in cn_words_dict]#替換inserts = [L + c + R for L, R in splits for c in cn_words_dict]#插入return set(deletes + transposes + replaces + inserts) #編輯距離生成的詞是否在我們前面得到的{詞:詞頻}列表里,是就返回5.找到候選正確詞集 。即編輯距離生成的詞同時又在數據庫.txt里的詞
#編輯距離生成的詞是否在我們前面得到的{詞:詞頻}列表里,是就返回 def known(phrases):return set(phrase for phrase in phrases if phrase in phrase_freq)6.計算拼音,得到一級數組,二級數組,三級數據。對候選正確詞進行分級
#得到錯誤短語的候選短語 #我們根據候選詞的拼音對其重要性進行排序 #如果候選詞的拼音與錯誤詞完全匹配,則將候選詞進行一級數組 #如果候選詞的第一個詞的拼音與錯誤詞的第一個詞匹配,我們將其按二級數組 #否則我們把候選短語放入第三個數組 def get_candidates(error_phrase):candidates_1st_order = []candidates_2nd_order = []candidates_3nd_order = []#pinyin.get,get使用一個簡單的get()函數,則可以返回拼音的符號,format="strip"去掉音調, delimiter="/"拼音之間的分隔符error_pinyin = pinyin.get(error_phrase, format="strip", delimiter="/")#錯誤拼音error_pinyin=str(error_pinyin)#轉換成字符串格式,為后面選擇拼音打下基礎cn_words_dict = load_cn_words_dict("cn_dict.txt")#導入單字candidate_phrases = list(edits1(error_phrase, cn_words_dict))#編輯距離生成的候選詞組for candidate_phrase in candidate_phrases:#遍歷編輯距離生成的候選詞組candidate_pinyin = pinyin.get(candidate_phrase, format="strip", delimiter="/")#候選詞拼音candidate_pinyin=str(candidate_pinyin)if candidate_pinyin == error_pinyin: # 如果錯誤詞拼音等于候選詞拼音,則加入第一選擇candidates_1st_order.append(candidate_phrase)elif candidate_pinyin.split("/")[0] == error_pinyin.split("/")[0]:candidates_2nd_order.append(candidate_phrase)else:candidates_3nd_order.append(candidate_phrase)#否則加入第三個return candidates_1st_order, candidates_2nd_order, candidates_3nd_order7.找到正確單詞
#自動更正單詞 def auto_correct(error_phrase):c1_order, c2_order, c3_order = get_candidates(error_phrase)#得到的候選正確詞# print c1_order, c2_order, c3_ordervalue1,value2,value3 = [],[],[]if c1_order:for i1 in c1_order:if i1 in phrase_freq:value1.append(i1)return (max(value1, key=phrase_freq.get))#一級候選存在,如果候選詞拼音與錯誤單詞完全正確,則返回候選詞詞頻最大的單詞elif c2_order:for i2 in c2_order:if i2 in phrase_freq:value2.append(i2)return (max(value2, key=phrase_freq.get))#一級候選不存在,二級候選存在,返回二級候選詞頻最大的詞else:for i3 in c3_order:if i3 in phrase_freq:value3.append(i3)return(max(value3, key=phrase_freq.get))#否則,返回三級候選詞頻最大的8.測試 對一個句子進行分詞 ,然后每個單詞 拿去尋找正確單詞 ,最后將這些詞拼接為正確句子
#對于任何一個給定的句子,用結巴做分詞, #割完成后,檢查word_freq dict中是否存在剩余的短語,如果不存在,則它是拼寫錯誤的短語 #使用auto_correct函數糾正拼寫錯誤的短語 #輸出正確的句子def auto_correct_sentence(error_sentence, verbose=True):jieba_cut = jieba.cut(error_sentence, cut_all=False)seg_list = "\t".join(jieba_cut).split("\t") # 分詞correct_sentence = ""for phrase in seg_list:correct_phrase = phrase # 當前詞語if phrase not in PUNCTUATION_LIST: # 去除標點符號if phrase not in phrase_freq.keys():correct_phrase = auto_correct(phrase) # 對當前學習進行修正if True:print(phrase, correct_phrase)correct_sentence += correct_phrasereturn correct_sentence9.主函數
def main():errsent = '重慶是中國的四大火爐之一,因風景銹麗,是"人間天棠"!'print("測試 :")correct_sent = auto_correct_sentence(errsent)print("原始文本:" + errsent + "\n==>\n" + "修正后的文本:" + correct_sent)if __name__ == "__main__":main()結果:
全文代碼:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Author: yudengwu # @Date : 2020/6/22 import sys import pinyin import jieba import string import rePUNCTUATION_LIST = string.punctuation # 標點符號!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ PUNCTUATION_LIST += "。,?:;{}[]‘“”《》/!%……()" # 添加額外標點符號#統計個單詞的詞頻 def construct_dict(file_path):word_freq = {}with open(file_path, "r",encoding='utf-8') as f:for line in f:info = line.split()word = info[0]frequency = info[1]word_freq[word] = frequencyreturn word_freqFILE_PATH = "token_freq_pos%40350k_jieba.txt" phrase_freq = construct_dict( FILE_PATH ) #得到的是各單詞詞頻,如:{'老師上課': '3', '老師傅': '62', '老師宿儒': '老師上課': '3', '老師傅': '62', }#構建一個自動更正 """ 為拼寫錯誤的短語創建一個自動更正器,我們使用編輯距離為拼寫錯誤的短語創建一個正確的候選列表 根據是正確短語的可能性對正確候選列表進行排序以下規則: 如果候選的拼音與拼寫錯誤的短語的拼音完全匹配,我們將候選按第一順序排列,這意味著他們是最有可能被選中的短語。 否則,如果候選的第一個單詞的拼音與拼寫錯誤的短語的第一個單詞的拼音匹配,我們就輸入第二個順序的候選者 否則,我們將候選對象按三階排序 """ import pinyin#載入編輯距離的單詞列表 #cn_words_dict 用于編輯距離的,從里面選擇字來菜如或者替換目標詞 def load_cn_words_dict( file_path ):cn_words_dict = ""with open(file_path, "r",encoding='utf-8') as f:for word in f:cn_words_dict += word.strip()#去除首尾空格return cn_words_dict cn_words_dict = load_cn_words_dict("cn_dict.txt")#導入單字#函數計算與中文短語的距離 #cn_words_dict 用于編輯距離的,從里面選擇字來菜如或者替換目標詞 def edits1(phrase, cn_words_dict):"`所有的編輯都是一個編輯遠離'短語."#phrase = phrase.decode("utf-8")splits = [(phrase[:i], phrase[i:]) for i in range(len(phrase) + 1)]#將單詞前后分開deletes = [L + R[1:] for L, R in splits if R]#刪除transposes = [L + R[1] + R[0] + R[2:] for L, R in splits if len(R)>1]#轉換replaces = [L + c + R[1:] for L, R in splits if R for c in cn_words_dict]#替換inserts = [L + c + R for L, R in splits for c in cn_words_dict]#插入return set(deletes + transposes + replaces + inserts) #編輯距離生成的詞是否在我們前面得到的{詞:詞頻}列表里,是就返回 def known(phrases):return set(phrase for phrase in phrases if phrase in phrase_freq)#得到錯誤短語的候選短語 #我們根據候選詞的拼音對其重要性進行排序 #如果候選詞的拼音與錯誤詞完全匹配,則將候選詞進行一級數組 #如果候選詞的第一個詞的拼音與錯誤詞的第一個詞匹配,我們將其按二級數組 #否則我們把候選短語放入第三個數組 def get_candidates(error_phrase):candidates_1st_order = []candidates_2nd_order = []candidates_3nd_order = []#pinyin.get,get使用一個簡單的get()函數,則可以返回拼音的符號,format="strip"去掉音調, delimiter="/"拼音之間的分隔符error_pinyin = pinyin.get(error_phrase, format="strip", delimiter="/")#錯誤拼音error_pinyin=str(error_pinyin)#轉換成字符串格式,為后面選擇拼音打下基礎cn_words_dict = load_cn_words_dict("cn_dict.txt")#導入單字candidate_phrases = list(edits1(error_phrase, cn_words_dict))#編輯距離生成的候選詞組for candidate_phrase in candidate_phrases:#遍歷編輯距離生成的候選詞組candidate_pinyin = pinyin.get(candidate_phrase, format="strip", delimiter="/")#候選詞拼音candidate_pinyin=str(candidate_pinyin)if candidate_pinyin == error_pinyin: # 如果錯誤詞拼音等于候選詞拼音,則加入第一選擇candidates_1st_order.append(candidate_phrase)elif candidate_pinyin.split("/")[0] == error_pinyin.split("/")[0]:candidates_2nd_order.append(candidate_phrase)else:candidates_3nd_order.append(candidate_phrase)#否則加入第三個return candidates_1st_order, candidates_2nd_order, candidates_3nd_order#自動更正單詞 def auto_correct(error_phrase):c1_order, c2_order, c3_order = get_candidates(error_phrase)#得到的候選正確詞# print c1_order, c2_order, c3_ordervalue1,value2,value3 = [],[],[]if c1_order:for i1 in c1_order:if i1 in phrase_freq:value1.append(i1)return (max(value1, key=phrase_freq.get))#一級候選存在,如果候選詞拼音與錯誤單詞完全正確,則返回候選詞詞頻最大的單詞elif c2_order:for i2 in c2_order:if i2 in phrase_freq:value2.append(i2)return (max(value2, key=phrase_freq.get))#一級候選不存在,二級候選存在,返回二級候選詞頻最大的詞else:for i3 in c3_order:if i3 in phrase_freq:value3.append(i3)return(max(value3, key=phrase_freq.get))#否則,返回三級候選詞頻最大的 ##對于任何一個給定的句子,用結巴做分詞, #割完成后,檢查word_freq dict中是否存在剩余的短語,如果不存在,則它是拼寫錯誤的短語 #使用auto_correct函數糾正拼寫錯誤的短語 #輸出正確的句子def auto_correct_sentence(error_sentence, verbose=True):jieba_cut = jieba.cut(error_sentence, cut_all=False)seg_list = "\t".join(jieba_cut).split("\t") # 分詞correct_sentence = ""for phrase in seg_list:correct_phrase = phrase # 當前詞語if phrase not in PUNCTUATION_LIST: # 去除標點符號if phrase not in phrase_freq.keys():correct_phrase = auto_correct(phrase) # 對當前學習進行修正if True:print(phrase, correct_phrase)correct_sentence += correct_phrasereturn correct_sentencedef main():errsent = '重慶是中國的四大火爐之一,因風景銹麗,是"人間天棠"!'print("測試 :")correct_sent = auto_correct_sentence(errsent)print("原始文本:" + errsent + "\n==>\n" + "修正后的文本:" + correct_sent)if __name__ == "__main__":main()來源# @Author: yudengwu
資源鏈接:
文中所用的停用詞表:中文文本糾錯數據集.zip
作者:電氣-余登武。
總結
以上是生活随笔為你收集整理的中文文本纠错 算例实现(有算例完整代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 美国、巴西、俄罗斯、印度那个国家出口粮食
- 下一篇: pyqt5讲解11:自定义信号和槽