Python自然語言處理詞匯分析技術實戰(zhàn)
摘要
本系列為自然語言處理導論與Python實踐系列的第一篇,主要對詞匯分析進行介紹,一些語言方面的基礎知識(詞性、詞語規(guī)范化)需要大家自行閱讀《自然語言處理導論》第二章。詞匯分析主要包含分詞與詞性標注兩部分,分詞部分將以中文分詞為例進行介紹。
最近在學習自然語言處理也可以說是入門,找到了一本覺得比較好的書《自然語言處理導論》,但是我在閱讀的過程中發(fā)現(xiàn)缺少了對應的代碼實踐,所以就萌生了完成對應算法的Python實踐的想法。通過復現(xiàn)對應的算法也能夠加深對算法的理解。本系列將根據(jù)《自然語言處理導論》書中的脈絡復現(xiàn)對應的算法,也是非常適合小白入門學習,我們大家一起學習,如有錯誤的地方歡迎在評論區(qū)指正。此外,本系列教程將從書中開始有算法的地方進行介紹,略過了一些理論部分,包括自然語言處理的基本概念、處理范式;等前置基礎知識,大家可以通過閱讀《自然語言處理導論》來跟上本教程的節(jié)奏。
詞匯分析
本系列為自然語言處理導論與Python實踐系列的第一篇,主要對詞匯分析進行介紹,一些語言方面的基礎知識(詞性、詞語規(guī)范化)需要大家自行閱讀《自然語言處理導論》第二章。詞匯分析主要包含分詞與詞性標注兩部分,分詞部分將以中文分詞為例進行介紹。
中文分詞
中文分詞(Chinese Word Segmentation,CWS)是指將連續(xù)字序列轉換為對應的詞序列的過程,也 可以看做在輸入的序列中添加空格或其他邊界標記的過程。中文分詞任務可以形式化表示為:給定中文句子 c1,c2,⋅⋅⋅,cn,c1,c2,⋅⋅⋅,cn, 其中 cici 為單個字符,輸出詞序列 w1,w2,⋅⋅⋅,wm,w1,w2,⋅⋅⋅,wm, 其中 wjwj 是中文單詞。
例如:
復旦大學是中國人自主創(chuàng)辦的第一所高等院校。
分詞結果:復旦大學 | 是 | 中國人 | 自主 | 創(chuàng)辦 | 的 | 第一 | 所 | 高等 | 院校 |。
基于最大匹配的中文分詞
最大匹配(Maximum Matching)分詞算法主要包含前向最大匹配,后向最大匹配以及雙向最大匹配等三類。在這里我們以正向匹配為例對該算法進行介紹。
例如:針對句子 “他是研究生物化學的一位科學家”,前向最大分詞的過程如表2.2所示。為簡單起見,詞典中詞語最大長度假設為 4,詞表為 {“他”,“是”, “研究”, “生物化學”, “的”, “一”, “位”, “科學家”}。如上圖。我們固定住頭,即『他』。我們從句子末尾開始向前找,“他是研究”有沒有在詞典里。有,就當成分詞。不是的話前移,直到『他』;依次類推,直到完成整個句子的切分,下面將通過代碼展示前向最大匹配算法流程。
前向最大匹配算法(Forward Max Matching,F(xiàn)MM)
dic=['他','是', '研究', '生物化學', '的', '一', '位', '科學家'] sentence = "他是研究生物化學的一位科學家" start = 0 while start != len(sentence): index = len(sentence) for i in range(len(sentence)): if sentence[start : index] in dic: print(sentence[start : index], end='/') start = index break index += -1
他/是/研究/生物化學/的/一/位/科學家/
后向最大匹配算法(Backward Max Matching,BMM)
dic=['他','是', '研究', '生物化學', '的', '一', '位', '科學家'] sentence = "他是研究生物化學的一位科學家" result = [] start = len(sentence) while start != 0: index = 0 for i in range(len(sentence)): if sentence[index: start] in dic: result.append(sentence[index:start]) start = index break index += 1 for i in result[::-1]: print(i,end='/')
他/是/研究/生物化學/的/一/位/科學家/
在上面的代碼中,start為句子的起始下標,index為從后往前移動的下標。while循環(huán)每次找出一個分詞。當start移到句子的最后一位上結束循環(huán)。內部的for循環(huán)是index移動過程,sentence[start:index]在詞典里面時,就跳出循環(huán)。更新start值,尋找下一個分詞。反向最大匹配算法與前向最大匹配算法類似,index從前往后移動即可,但要注意輸出需要反轉一下。
擴展閱讀
對于FMM,BMM的分詞結果,可以通過指定規(guī)則來確定最終結果。兩種方法的分詞結果,選擇分詞數(shù)最少的;分詞數(shù)一樣的再判斷句子中的單字數(shù),誰的單字數(shù)越少,就誰的認為分詞效果越好。即為雙向最大匹配算法(Backward Max Matching,BIMM)
基于詞典的分詞方法優(yōu)缺點
- 簡單、快速、可控、僅依賴詞表
- 沒有在詞典中出現(xiàn)的詞沒有很好的處理方案,同時對于分詞歧義的處理能力也不足
基于線性鏈條件隨機場的中文分詞
簡單來說基于線性鏈條件隨機場的中文分詞,就是通過條件隨機場對句子的輸入序列進行建模,完成分詞的過程,對序列任務進行建模時,通常使用鏈式結構,即線性鏈條件隨機場(Linear-chain CRF)。根據(jù)中文分詞任務定義,我們可以將分詞過程看做是對于字的分類。具體來說,對于輸入句子中的每一個字$ ci,根據(jù)它在分詞結果中的位置賦予不同的標簽??梢约僭O一個字在詞語中有四個位置:開始,根據(jù)它在分詞結果中的位置賦予不同的標簽??梢约僭O一個字在詞語中有四個位置:開始(B)、中間、中間(I)、結尾、結尾(E)以及單獨成詞以及單獨成詞(S)$。
例如:
輸入句子:他是研究生物化學的一位科學家。
分詞結果:他 | 是 | 研究 | 生物化學 | 的 | 一 | 位 | 科學家 |。
對應標記:他/S 是/S 研/B 究/E 生/B 物/I 化/I 學/E 的/S 一/B 位/E 科/B 學/I 家/E 。/S
這里的“字”不僅包含漢字,還包含英文字母、數(shù)字、標點符號等所有可能出現(xiàn)在漢語文本中的符號。通過 BIESBIES 標簽可以將分詞問題轉換為字的分類問題。
條件隨機場(Conditional Random Field,CRF)試圖對多個變量在給定觀測值后的條件概率進行建模。x=xl,x2,...,xnx=xl,x2,...,xn 為觀測序列,y=yl,y2,...,yny=yl,y2,...,yn 為對應的標記序列,條件隨機場的目標是構建條件概率模型 P(y∣x)P(y∣x)。在中文分詞任務中,觀察序列 xx 對應輸入的字序列 c1,c2,⋅⋅⋅,cnc1,c2,⋅⋅⋅,cn,標記序列為每個字對應的 BIESBIES 標簽。在實際應用中,對序列任務進行建模時,通常使用如下圖示的鏈式結構,即線性鏈條件隨機場(Linear-chain CRF)。
條件隨機場(CRF)由Lafferty等人于2001年提出,結合了最大熵模型和隱馬爾可夫模型的特點,是一種無向圖模型,常用于標注或分析序列資料,如自然語言文字或是生物序列。近年來在分詞、詞性標注和命名實體識別等序列標注任務中取得了很好的效果。
安裝CRF++的python庫
!pip install crfpy
將訓練語料標注成B M E S存儲
def character_tagging(input_file,output_file): input_data = open(input_file,'r',encoding='UTF-8-sig') output_data = open(output_file,'w',encoding='UTF-8-sig') for line in input_data.readlines(): word_list = line.strip().split() for word in word_list: if len(word)==1: output_data.write(word+'\tS\n') else: output_data.write(word[0]+'\tB\n') for w in word[1:len(word)-1]: output_data.write(w+'\tM\n') output_data.write(word[len(word)-1]+'\tE\n') output_data.write('\n') input_data.close() output_data.close() character_tagging('pku_training.utf8','pku_training_out.utf8')
使用CRF++工具訓練條件隨機場中文分詞模型
需要注意的是,模型訓練迭代次數(shù)默認為10k,此處為了方便演示,僅僅設置了10次,如果需要較好的模型效果,建議按照默認的迭代次數(shù)進行訓練。另外大家可以在終端中直接輸入crf_learn
查看其命令參數(shù)的含義。
!crf_learn -f 3 -m 10 -c 4.0 template pku_training_out.utf8 crf_model
使用訓練好的模型輸出結果
import codecs import sys import CRFPP def crf_segmenter(input_file, output_file, tagger): input_data = codecs.open(input_file, 'r', 'utf-8') output_data = codecs.open(output_file, 'w', 'utf-8') for line in input_data.readlines(): tagger.clear() for word in line.strip(): word = word.strip() if word: tagger.add((word + "\to\tB").encode('utf-8')) tagger.parse() size = tagger.size() xsize = tagger.xsize() for i in range(0, size): for j in range(0, xsize): char = tagger.x(i, j).decode('utf-8') tag = tagger.y2(i) if tag == 'B': output_data.write(' ' + char) elif tag == 'M': output_data.write(char) elif tag == 'E': output_data.write(char + ' ') else: output_data.write(' ' + char + ' ') output_data.write('\n') input_data.close() output_data.close() crf_model = crf_model input_file = pku_training_out.utf8 output_file = pku_training_out_crf.utf8 tagger = CRFPP.Tagger("-m " + crf_model) crf_segmenter(input_file, output_file, tagger)
CRF++庫簡介
CRF++ 是條件隨機場 (CRF) 的簡單、可定制和開源實現(xiàn),用于分割/標記順序數(shù)據(jù)。 CRF++ 專為通用目的而設計,將應用于各種 NLP 任務,例如命名實體識別、信息提取和文本分塊。
總結
基于線性鏈條件隨機場中文分詞方法可以有效地平衡訓練語料中出現(xiàn)的詞語和未登錄詞,并且可以使用模板特征引入詞典信息。相較于基于詞典的方法,基于線性鏈條件隨機場中文分詞方法通??梢允÷晕吹卿浽~的識別模塊。但是需要注意的是,基于線性鏈條件隨機場的方法只能使用字作為特征。
經(jīng)過上面的介紹,相信大家對中文分詞方法已經(jīng)有了一些認識,但是一些其他的基礎知識需要大家仔細閱讀相關書籍,包括什么是未登錄詞、詞素、漢藏語系、閃含語系、印歐語系等,大家都要有了解。下一期將和大家一起學習基于感知機的中文分詞算法,并且會根據(jù)相關論文進行介紹。大家一起加油哦!希望大家以后多多支持腳本之家!
相關文章
python開發(fā)實例之python使用Websocket庫開發(fā)簡單聊天工具實例詳解(python+Websocket+J
這篇文章主要介紹了python開發(fā)實例之python使用Websocket庫開發(fā)簡單聊天工具實例詳解(python+Websocket+JS),需要的朋友可以參考下2020-03-03Python查詢oracle數(shù)據(jù)庫速度慢的解決方案
這篇文章主要介紹了Python查詢oracle數(shù)據(jù)庫速度慢的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04Django makemigrations migrate執(zhí)行成功但不創(chuàng)建數(shù)據(jù)庫表的解決
這篇文章主要介紹了Django makemigrations migrate執(zhí)行成功但不創(chuàng)建數(shù)據(jù)庫表的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09opencv+tesseract實現(xiàn)驗證碼識別的示例
本文主要介紹了opencv+tesseract實現(xiàn)驗證碼識別的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-06-06Python中利用ItsDangerous快捷實現(xiàn)數(shù)據(jù)加密
這篇文章主要介紹了Python中利用ItsDangerous快捷實現(xiàn)數(shù)據(jù)加密,通過使用Python庫ItsDangerous,我們就可以高效快捷地完成數(shù)據(jù)加密/解密的過程,本文結合實例代碼給大家講解的非常詳細,需要的朋友可以參考下2022-11-11