Python自然語(yǔ)言處理詞匯分析技術(shù)實(shí)戰(zhàn)
摘要
本系列為自然語(yǔ)言處理導(dǎo)論與Python實(shí)踐系列的第一篇,主要對(duì)詞匯分析進(jìn)行介紹,一些語(yǔ)言方面的基礎(chǔ)知識(shí)(詞性、詞語(yǔ)規(guī)范化)需要大家自行閱讀《自然語(yǔ)言處理導(dǎo)論》第二章。詞匯分析主要包含分詞與詞性標(biāo)注兩部分,分詞部分將以中文分詞為例進(jìn)行介紹。

最近在學(xué)習(xí)自然語(yǔ)言處理也可以說(shuō)是入門(mén),找到了一本覺(jué)得比較好的書(shū)《自然語(yǔ)言處理導(dǎo)論》,但是我在閱讀的過(guò)程中發(fā)現(xiàn)缺少了對(duì)應(yīng)的代碼實(shí)踐,所以就萌生了完成對(duì)應(yīng)算法的Python實(shí)踐的想法。通過(guò)復(fù)現(xiàn)對(duì)應(yīng)的算法也能夠加深對(duì)算法的理解。本系列將根據(jù)《自然語(yǔ)言處理導(dǎo)論》書(shū)中的脈絡(luò)復(fù)現(xiàn)對(duì)應(yīng)的算法,也是非常適合小白入門(mén)學(xué)習(xí),我們大家一起學(xué)習(xí),如有錯(cuò)誤的地方歡迎在評(píng)論區(qū)指正。此外,本系列教程將從書(shū)中開(kāi)始有算法的地方進(jìn)行介紹,略過(guò)了一些理論部分,包括自然語(yǔ)言處理的基本概念、處理范式;等前置基礎(chǔ)知識(shí),大家可以通過(guò)閱讀《自然語(yǔ)言處理導(dǎo)論》來(lái)跟上本教程的節(jié)奏。
詞匯分析
本系列為自然語(yǔ)言處理導(dǎo)論與Python實(shí)踐系列的第一篇,主要對(duì)詞匯分析進(jìn)行介紹,一些語(yǔ)言方面的基礎(chǔ)知識(shí)(詞性、詞語(yǔ)規(guī)范化)需要大家自行閱讀《自然語(yǔ)言處理導(dǎo)論》第二章。詞匯分析主要包含分詞與詞性標(biāo)注兩部分,分詞部分將以中文分詞為例進(jìn)行介紹。
中文分詞
中文分詞(Chinese Word Segmentation,CWS)是指將連續(xù)字序列轉(zhuǎn)換為對(duì)應(yīng)的詞序列的過(guò)程,也 可以看做在輸入的序列中添加空格或其他邊界標(biāo)記的過(guò)程。中文分詞任務(wù)可以形式化表示為:給定中文句子 c1,c2,⋅⋅⋅,cn,c1,c2,⋅⋅⋅,cn, 其中 cici 為單個(gè)字符,輸出詞序列 w1,w2,⋅⋅⋅,wm,w1,w2,⋅⋅⋅,wm, 其中 wjwj 是中文單詞。
例如:
復(fù)旦大學(xué)是中國(guó)人自主創(chuàng)辦的第一所高等院校。
分詞結(jié)果:復(fù)旦大學(xué) | 是 | 中國(guó)人 | 自主 | 創(chuàng)辦 | 的 | 第一 | 所 | 高等 | 院校 |。
基于最大匹配的中文分詞
最大匹配(Maximum Matching)分詞算法主要包含前向最大匹配,后向最大匹配以及雙向最大匹配等三類。在這里我們以正向匹配為例對(duì)該算法進(jìn)行介紹。

例如:針對(duì)句子 “他是研究生物化學(xué)的一位科學(xué)家”,前向最大分詞的過(guò)程如表2.2所示。為簡(jiǎn)單起見(jiàn),詞典中詞語(yǔ)最大長(zhǎng)度假設(shè)為 4,詞表為 {“他”,“是”, “研究”, “生物化學(xué)”, “的”, “一”, “位”, “科學(xué)家”}。如上圖。我們固定住頭,即『他』。我們從句子末尾開(kāi)始向前找,“他是研究”有沒(méi)有在詞典里。有,就當(dāng)成分詞。不是的話前移,直到『他』;依次類推,直到完成整個(gè)句子的切分,下面將通過(guò)代碼展示前向最大匹配算法流程。
前向最大匹配算法(Forward Max Matching,F(xiàn)MM)
dic=['他','是', '研究', '生物化學(xué)', '的', '一', '位', '科學(xué)家']
sentence = "他是研究生物化學(xué)的一位科學(xué)家"
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
他/是/研究/生物化學(xué)/的/一/位/科學(xué)家/
后向最大匹配算法(Backward Max Matching,BMM)
dic=['他','是', '研究', '生物化學(xué)', '的', '一', '位', '科學(xué)家']
sentence = "他是研究生物化學(xué)的一位科學(xué)家"
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='/')
他/是/研究/生物化學(xué)/的/一/位/科學(xué)家/
在上面的代碼中,start為句子的起始下標(biāo),index為從后往前移動(dòng)的下標(biāo)。while循環(huán)每次找出一個(gè)分詞。當(dāng)start移到句子的最后一位上結(jié)束循環(huán)。內(nèi)部的for循環(huán)是index移動(dòng)過(guò)程,sentence[start:index]在詞典里面時(shí),就跳出循環(huán)。更新start值,尋找下一個(gè)分詞。反向最大匹配算法與前向最大匹配算法類似,index從前往后移動(dòng)即可,但要注意輸出需要反轉(zhuǎn)一下。
擴(kuò)展閱讀
對(duì)于FMM,BMM的分詞結(jié)果,可以通過(guò)指定規(guī)則來(lái)確定最終結(jié)果。兩種方法的分詞結(jié)果,選擇分詞數(shù)最少的;分詞數(shù)一樣的再判斷句子中的單字?jǐn)?shù),誰(shuí)的單字?jǐn)?shù)越少,就誰(shuí)的認(rèn)為分詞效果越好。即為雙向最大匹配算法(Backward Max Matching,BIMM)
基于詞典的分詞方法優(yōu)缺點(diǎn)
- 簡(jiǎn)單、快速、可控、僅依賴詞表
- 沒(méi)有在詞典中出現(xiàn)的詞沒(méi)有很好的處理方案,同時(shí)對(duì)于分詞歧義的處理能力也不足
基于線性鏈條件隨機(jī)場(chǎng)的中文分詞
簡(jiǎn)單來(lái)說(shuō)基于線性鏈條件隨機(jī)場(chǎng)的中文分詞,就是通過(guò)條件隨機(jī)場(chǎng)對(duì)句子的輸入序列進(jìn)行建模,完成分詞的過(guò)程,對(duì)序列任務(wù)進(jìn)行建模時(shí),通常使用鏈?zhǔn)浇Y(jié)構(gòu),即線性鏈條件隨機(jī)場(chǎng)(Linear-chain CRF)。根據(jù)中文分詞任務(wù)定義,我們可以將分詞過(guò)程看做是對(duì)于字的分類。具體來(lái)說(shuō),對(duì)于輸入句子中的每一個(gè)字$ ci,根據(jù)它在分詞結(jié)果中的位置賦予不同的標(biāo)簽。可以假設(shè)一個(gè)字在詞語(yǔ)中有四個(gè)位置:開(kāi)始,根據(jù)它在分詞結(jié)果中的位置賦予不同的標(biāo)簽??梢约僭O(shè)一個(gè)字在詞語(yǔ)中有四個(gè)位置:開(kāi)始(B)、中間、中間(I)、結(jié)尾、結(jié)尾(E)以及單獨(dú)成詞以及單獨(dú)成詞(S)$。
例如:
輸入句子:他是研究生物化學(xué)的一位科學(xué)家。
分詞結(jié)果:他 | 是 | 研究 | 生物化學(xué) | 的 | 一 | 位 | 科學(xué)家 |。
對(duì)應(yīng)標(biāo)記:他/S 是/S 研/B 究/E 生/B 物/I 化/I 學(xué)/E 的/S 一/B 位/E 科/B 學(xué)/I 家/E 。/S
這里的“字”不僅包含漢字,還包含英文字母、數(shù)字、標(biāo)點(diǎn)符號(hào)等所有可能出現(xiàn)在漢語(yǔ)文本中的符號(hào)。通過(guò) BIESBIES 標(biāo)簽可以將分詞問(wèn)題轉(zhuǎn)換為字的分類問(wèn)題。
條件隨機(jī)場(chǎng)(Conditional Random Field,CRF)試圖對(duì)多個(gè)變量在給定觀測(cè)值后的條件概率進(jìn)行建模。x=xl,x2,...,xnx=xl,x2,...,xn 為觀測(cè)序列,y=yl,y2,...,yny=yl,y2,...,yn 為對(duì)應(yīng)的標(biāo)記序列,條件隨機(jī)場(chǎng)的目標(biāo)是構(gòu)建條件概率模型 P(y∣x)P(y∣x)。在中文分詞任務(wù)中,觀察序列 xx 對(duì)應(yīng)輸入的字序列 c1,c2,⋅⋅⋅,cnc1,c2,⋅⋅⋅,cn,標(biāo)記序列為每個(gè)字對(duì)應(yīng)的 BIESBIES 標(biāo)簽。在實(shí)際應(yīng)用中,對(duì)序列任務(wù)進(jìn)行建模時(shí),通常使用如下圖示的鏈?zhǔn)浇Y(jié)構(gòu),即線性鏈條件隨機(jī)場(chǎng)(Linear-chain CRF)。

條件隨機(jī)場(chǎng)(CRF)由Lafferty等人于2001年提出,結(jié)合了最大熵模型和隱馬爾可夫模型的特點(diǎn),是一種無(wú)向圖模型,常用于標(biāo)注或分析序列資料,如自然語(yǔ)言文字或是生物序列。近年來(lái)在分詞、詞性標(biāo)注和命名實(shí)體識(shí)別等序列標(biāo)注任務(wù)中取得了很好的效果。
安裝CRF++的python庫(kù)
!pip install crfpy
將訓(xùn)練語(yǔ)料標(biāo)注成B M E S存儲(chǔ)
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++工具訓(xùn)練條件隨機(jī)場(chǎng)中文分詞模型
需要注意的是,模型訓(xùn)練迭代次數(shù)默認(rèn)為10k,此處為了方便演示,僅僅設(shè)置了10次,如果需要較好的模型效果,建議按照默認(rèn)的迭代次數(shù)進(jìn)行訓(xùn)練。另外大家可以在終端中直接輸入crf_learn查看其命令參數(shù)的含義。
!crf_learn -f 3 -m 10 -c 4.0 template pku_training_out.utf8 crf_model
使用訓(xùn)練好的模型輸出結(jié)果
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++庫(kù)簡(jiǎn)介
CRF++ 是條件隨機(jī)場(chǎng) (CRF) 的簡(jiǎn)單、可定制和開(kāi)源實(shí)現(xiàn),用于分割/標(biāo)記順序數(shù)據(jù)。 CRF++ 專為通用目的而設(shè)計(jì),將應(yīng)用于各種 NLP 任務(wù),例如命名實(shí)體識(shí)別、信息提取和文本分塊。
總結(jié)
基于線性鏈條件隨機(jī)場(chǎng)中文分詞方法可以有效地平衡訓(xùn)練語(yǔ)料中出現(xiàn)的詞語(yǔ)和未登錄詞,并且可以使用模板特征引入詞典信息。相較于基于詞典的方法,基于線性鏈條件隨機(jī)場(chǎng)中文分詞方法通??梢允÷晕吹卿浽~的識(shí)別模塊。但是需要注意的是,基于線性鏈條件隨機(jī)場(chǎng)的方法只能使用字作為特征。
經(jīng)過(guò)上面的介紹,相信大家對(duì)中文分詞方法已經(jīng)有了一些認(rèn)識(shí),但是一些其他的基礎(chǔ)知識(shí)需要大家仔細(xì)閱讀相關(guān)書(shū)籍,包括什么是未登錄詞、詞素、漢藏語(yǔ)系、閃含語(yǔ)系、印歐語(yǔ)系等,大家都要有了解。下一期將和大家一起學(xué)習(xí)基于感知機(jī)的中文分詞算法,并且會(huì)根據(jù)相關(guān)論文進(jìn)行介紹。大家一起加油哦!希望大家以后多多支持腳本之家!
相關(guān)文章
python開(kāi)發(fā)實(shí)例之python使用Websocket庫(kù)開(kāi)發(fā)簡(jiǎn)單聊天工具實(shí)例詳解(python+Websocket+J
這篇文章主要介紹了python開(kāi)發(fā)實(shí)例之python使用Websocket庫(kù)開(kāi)發(fā)簡(jiǎn)單聊天工具實(shí)例詳解(python+Websocket+JS),需要的朋友可以參考下2020-03-03
python溫度轉(zhuǎn)換華氏溫度實(shí)現(xiàn)代碼
這篇文章主要介紹了python溫度轉(zhuǎn)換華氏溫度實(shí)現(xiàn)代碼內(nèi)容,有需要的朋友們可以測(cè)試下。2020-12-12
Python查詢oracle數(shù)據(jù)庫(kù)速度慢的解決方案
這篇文章主要介紹了Python查詢oracle數(shù)據(jù)庫(kù)速度慢的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
Django makemigrations migrate執(zhí)行成功但不創(chuàng)建數(shù)據(jù)庫(kù)表的解決
這篇文章主要介紹了Django makemigrations migrate執(zhí)行成功但不創(chuàng)建數(shù)據(jù)庫(kù)表的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
opencv+tesseract實(shí)現(xiàn)驗(yàn)證碼識(shí)別的示例
本文主要介紹了opencv+tesseract實(shí)現(xiàn)驗(yàn)證碼識(shí)別的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Python中利用ItsDangerous快捷實(shí)現(xiàn)數(shù)據(jù)加密
這篇文章主要介紹了Python中利用ItsDangerous快捷實(shí)現(xiàn)數(shù)據(jù)加密,通過(guò)使用Python庫(kù)ItsDangerous,我們就可以高效快捷地完成數(shù)據(jù)加密/解密的過(guò)程,本文結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2022-11-11
Django應(yīng)用程序中如何發(fā)送電子郵件詳解
我們常常會(huì)用到一些發(fā)送郵件的功能,比如有人提交了應(yīng)聘的表單,可以向HR的郵箱發(fā)郵件,這樣,HR不看網(wǎng)站就可以知道有人在網(wǎng)站上提交了應(yīng)聘信息。下面這篇文章就介紹了在Django應(yīng)用程序中如何發(fā)送電子郵件的相關(guān)資料,需要的朋友可以參考借鑒。2017-02-02

