Python自然語言處理實戰(4):詞性標註與命名實體識別
4.1 詞性標註
詞性是詞彙基本的語法屬性,通常也稱為詞類。從整體上看,大多數詞語,尤其是實詞,一般只有一到兩個詞性,且其中一個詞性的使用頻次遠遠大於另一個,即使每次都將高頻詞性作為詞性選擇進行標註,也能實現80%以上的準確率。目前較為主流的方法是如同分詞一樣,將句子的詞性標註作為一個序列標註問題來解決。
較為主流的詞性標註規範有北大的詞性標註集和濱州詞性標註集兩大類。
jieba的詞性標註同樣是結合規則和統計的方式,具體為在詞性標註的過程中,詞典匹配和HMM共同作用。詞性標註流程如下:
1)首先基於正規表示式進行漢字判斷
re_han_internal = re.compile('([\u4E00-\u9FD5a-zA-Z0-9+#&\._]+)")
2) 若符合上面的正規表示式,則判定為漢字,然後基於字首詞典構建有向無環圖,再基於有向無環圖計算最大概率路徑,同時在字首詞典中找出它所分出的詞性,若在字典中未找到,則賦予詞性為“x"(代表未知)。當然,若在這個過程中,設定使用HMM,且待標註詞為未登入詞,則會通過HMM方式進行詞性標註。
3)若不符合上面的正規表示式,那麼將繼續通過正規表示式進行型別判斷,分別賦予”x" "m"(數詞)和"eng"(英文)
在詞性標註任務中,Jieba分詞采用了simultaneous思想的聯合模型方法,即將基於字標註的分詞方法和詞性標註結合起來,使用複合標註集。比如名詞“人民”,“人”為B_n,民為E_n。這樣就與HMM分詞的實現過程一致,只需要更換合適的訓練語料即可。
>>> import jieba.posseg as psg
>>> sent = "中文分詞是文字處理不可或缺的一步!"
>>> seg_list = psg.cut(sent)
>>> print(' '.join(['{0}/{1}'.format(w, t) for w, t in seg_list]))
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 0.864 seconds.
Prefix dict has been built succesfully.
中文/nz 分詞/n 是/v 文字處理/n 不可或缺/l 的/uj 一步/m !/x
4.2 命名實體識別
NER目的是識別語料中人名、地名、組織機構名等命名實體。命名實體一般分為3大類(實體類、時間類、數字類)和7小類(人名、地名、組織機構名、時間、日期、貨幣、百分比)。由於數量、時間、日期、貨幣等實體識別通常可以採用模式匹配的方式獲得較好的識別效果,相比之下人名、地名、機構名較複雜,因此近年來的研究主要以這幾種實體為主。
序列標註方式是目前命名實體識別中的主流方法。
在大量真實語料中,觀察序列更多的是以一種多重的互動特徵形式表現出來,觀察元素之間廣泛存在長程相關性。這樣,HMM的效果就受到了制約。基於此,在2001年,Lafferty等學者們提出了條件隨機場,其主要思想來源於HMM,也是一種用來標記和切分序列化資料的統計模型。不同的是,條件隨機場是在給定觀察的標記序列下,計算整個標記序列的聯合概率,而HMM是在給定當前狀態下,定義下一個狀態的分佈。
地名識別:
git clone https://github.com/taku910/crfpp.git
./configure
make && sudo make install
CRF++提供了Python使用介面
cd python
python setup.py build
sudo python setup.py install
使用CRF++地名識別主要有以下流程:
1、確定標籤體系
"B"
"E"
"M"
"S"
"O"
2、語料資料處理
CRF++的訓練資料要求一定的格式,一般是一行一個token,一句話由多行token組成,多個句子之間用空行分開。其中每行又分成多列,除最後一列以外,其他列表示特徵。因此一般至少需要兩列,最後一列表示要預測的標籤。本例使用
我 O
去 O
北 B
京 M
飯 M
店 E
。 O
採用的語料資料是1998年人民日報分詞資料集。對資料處理程式碼如下corpusHandler.py
# -*- coding: utf-8 -*-
# 每行的標註轉換
def tag_line(words, mark):
chars = []
tags = []
temp_word = '' #用於合併組合詞
for word in words:
#print(word)
word = word.strip('\t ')
if temp_word == '':
bracket_pos = word.find('[') # [ ]ns
w, h = word.split('/')
if bracket_pos == -1:
if len(w) == 0: continue
chars.extend(w)
if h == 'ns': # 地名
tags += ['S'] if len(w) == 1 else ['B'] + ['M'] * (len(w)-2) + ['E']
else:
tags += ['O'] * len(w)
else:
print(w)
w = w[bracket_pos+1:]
temp_word += w
else:
bracket_pos = word.find(']')
w, h = word.split('/')
if bracket_pos == -1:
temp_word += w
else:
print(w)
w = temp_word + w
h = word[bracket_pos+1:]
temp_word = ''
if len(w) == 0: continue
chars.extend(w)
if h == 'ns':
tags += ['S'] if len(w) == 1 else ['B']+['M']*(len(w)-2)+['E']
else:
tags += ['O']*len(w)
assert temp_word == ''
return (chars, tags)
def corpusHandler(corpusPath):
import os
root = os.path.dirname(corpusPath)
with open(corpusPath) as corpus_f, \
open(os.path.join(root, 'train.txt'), 'w') as train_f, \
open(os.path.join(root, 'test.txt'), 'w') as test_f:
pos = 0
for line in corpus_f:
line = line.strip('\r\n\t');
if line == '': continue
isTest = True if pos % 5 == 0 else False # 抽樣20%作為測試集使用
words = line.split()[1:]
if len(words) == 0: continue
line_chars, line_tags = tag_line(words, pos)
saveObj = test_f if isTest else train_f
for k, v in enumerate(line_chars):
saveObj.write(v + '\t' + line_tags[k] + '\n')
saveObj.write('\n')
pos += 1
if __name__ == '__main__':
corpusHandler('./data/people-daily.txt')
3、特徵模板設計
CRF的特徵函式是通過定一些規則來實現的,對應CRF++中的特徵模板。其基本格式為%x[row, col],用於確定輸入資料的一個token,其中,row確定與當前的token的相對行數,col用於確定決定列數。
CRF++有兩種模板型別,第一種是U開頭,為Unigram template,CRF++會自動為其生成一個特徵函式集合(func1...funcN)。第二種以B開頭,表示Bigram template,會自動產生當前輸出與前一個輸出token的組合,根據該組合構造特徵函式。
crf_learn -f 4 -p 8 -c 3 template ./data/train.txt model
crf_test -m model ./data/test.txt > ./data/test.rst
def f1(path):
with open(path) as f:
all_tag = 0
loc_tag = 0
pred_loc_tag = 0
correct_tag = 0
correct_loc_tag = 0
states = ['B', 'M', 'E', 'S']
for line in f:
line = line.strip()
if line == '': continue
_, r, p = line.split()
all_tag += 1
if r == p:
correct_tag += 1
if r in states:
correct_loc_tag += 1
if r in states: loc_tag += 1
if p in states: pred_loc_tag += 1
loc_P = 1.0 * correct_loc_tag/pred_loc_tag
loc_R = 1.0 * correct_loc_tag/loc_tag
print('loc_P:{0}, loc_R:{1}, loc_F1:{2}'.format(loc_P, loc_R, (2*loc_P*loc_R)/(loc_P+loc_R)))
if __name__ == '__main__':
f1('./data/test.rst')
def load_model(path):
import os, CRFPP
if os.path.exists(path):
return CRFPP.Tagger('-m {0} -v 3 -n2'.format(path))
return None
def locationNER(text):
tagger = load_model('./model')
for c in text:
tagger.add(c)
result = []
tagger.parse()
#print(tagger.xsize())
word = ''
for i in range(0, tagger.size()):
for j in range(0, tagger.xsize()):
ch = tagger.x(i, j)
#print(ch)
tag = tagger.y2(i)
#print(tag)
if tag == 'B':
word = ch
elif tag == 'M':
word += ch
elif tag == 'E':
word += ch
result.append(word)
elif tag == 'S':
word = ch
result.append(word)
return result
text = '我中午要去北京飯店,下午去中山公園,晚上回亞運村。'
print(text, locationNER(text), sep='==> ')
text = '我去回龍觀,不去南鑼鼓巷。'
print(text, locationNER(text), sep='==> ')
text = '打的去北京南站。'
print(text, locationNER(text), sep='==> ')
我中午要去北京飯店,下午去中山公園,晚上回亞運村。==> ['北京飯店', '中山公園', '亞運村']
我去回龍觀,不去南鑼鼓巷。==> []
打的去北京南站。==> ['北京']
如“回龍觀”等識別效果並不好,通常的解決辦法是:
1)擴充套件語料,改進模型。如加入詞性特徵,調整分詞演算法等。
2)整理地理位置詞庫。在識別時,先通過詞庫匹配,再採用模型進行發現。
相關文章
- 精通Python自然語言處理 4 :詞性標註--單詞識別Python自然語言處理詞性標註
- 詞!自然語言處理之詞全解和Python實戰!自然語言處理Python
- 自然語言處理工具pyhanlp分詞與詞性標註自然語言處理HanLP分詞詞性標註
- Python自然語言處理實戰(3):中文分詞技術Python自然語言處理中文分詞
- 《Python自然語言處理實戰》連結表Python自然語言處理
- 基於結構化感知機的詞性標註與命名實體識別框架詞性標註框架
- Pyhanlp自然語言處理中的新詞識別HanLP自然語言處理
- 自然語言處理工具python呼叫hanlp中文實體識別自然語言處理PythonHanLP
- Python自然語言處理實戰(1):NLP基礎Python自然語言處理
- 自然語言處理之序列標註問題自然語言處理
- 自然語言處理:分詞方法自然語言處理分詞
- 自然語言處理之jieba分詞自然語言處理Jieba分詞
- 自然語言處理的最佳實踐自然語言處理
- Python 自然語言處理(基於jieba分詞和NLTK)Python自然語言處理Jieba分詞
- 達觀資料CTO紀達麒:小標註資料量下自然語言處理實戰經驗自然語言處理
- 自然語言處理NLP(6)——詞法分析自然語言處理詞法分析
- 自然語言處理標註工具——Brat(安裝、測試、使用)自然語言處理
- 微調大型語言模型進行命名實體識別模型
- 《NLP漢語自然語言處理原理與實踐》學習四自然語言處理
- 2023nlp影片教程大全 NLP自然語言處理教程 自然語言處理NLP從入門到專案實戰自然語言處理
- 如何用Python處理自然語言?(Spacy與Word Embedding)Python
- IJCAI 2018 利用跨語言知識改進稀缺資源語言命名實體識別AI
- 05.序列模型 W2.自然語言處理與詞嵌入模型自然語言處理
- hanlp自然語言處理包的人名識別程式碼解析HanLP自然語言處理
- NPL---自然語言處理單詞界定問題自然語言處理
- 入門自然語言處理必看:圖解詞向量自然語言處理圖解
- 自然語言處理與情緒智慧自然語言處理
- 精通Python自然語言處理 2 :統計語言建模Python自然語言處理
- 精通Python自然語言處理 1 :字串操作Python自然語言處理字串
- 自然語言處理中的分詞問題總結自然語言處理分詞
- NLP自然語言處理中的hanlp分詞例項自然語言處理HanLP分詞
- Hanlp自然語言處理中的詞典格式說明HanLP自然語言處理
- python呼叫hanlp進行命名實體識別PythonHanLP
- 自然語言處理(NLP)系列(一)——自然語言理解(NLU)自然語言處理
- python的詞性標註Python詞性標註
- 基於keras的BiLstm與CRF實現命名實體標註KerasCRF
- HanLP 自然語言處理 for nodejsHanLP自然語言處理NodeJS
- 自然語言處理NLP(四)自然語言處理