一、命名實體識別簡單概要
按照類型標記每一個名詞:對句子名詞進行分類
我今天(時間)要去北京(地點)參加面試
張三(人名)出生於上海(地名),清華大學(組織)畢業後去百度(組織)任職。
命名實體識別:1、構建知識圖譜 2、聊天機器人
如:聊天機器人
機器人:先生,請問有什麼可以幫到您的嘛?
客戶:能不能幫我查詢一下明天中午(時間)從北京(地名)飛哈爾濱(地名)的機票?
|命名實體識別
{
時間:明天中午:11:00 - 13:00,
出發:北京 ----> searchForticket(from,to,time)(填槽) 數據庫 -->回覆(根據模版填槽)
達到:哈爾濱
}
目前又一個滿足要求的航班XXX
二、命名實體識別的評價指標
Contingency Table
correct | Not correct | |
selected | tp | fp |
not selected | fn | tn |
精確率: precision = tp/(tp + fp)
召回率: recall = tp/(tp+fn)
F1: F1 = 2PR/(P+R)
三、基於規則的命名實體識別
1、基於正則表達方式 2、基於已知的詞典庫(建立詞典庫-匹配(精確、模糊-規則、相似度算法上下文信息))
四、命名實體識別-分類問題
語料
-> 分詞 (名詞準確分爲指定的實體名)
-> 特徵提取(特徵1,特徵2,.....,特徵D)
-> 分類器 f(特徵1,特徵2.......特徵D)
張三 出生 於 北京, 北京大學 畢業 後 去 華爲 任職
X - 特徵 Y - label
(張三,-- ,出生,--,張三出生,人名,--,動詞) (人名)
(於,出生,北京,出生於,於北京,介詞,動詞,地名) (NA)
(北京,於,北京大學,於北京,北京北京大學,地名,介詞,組織) (地名)
(北京大學,北京,畢業,北京北京大學,北京大學畢業,組織,地名,動詞) (組織名)
(畢業,北京大學,後,北京大學畢業,畢業後,動詞,組織,方位詞) (NA)
命名實體識別-分類器:
1、時序無關模型:
邏輯迴歸、支持向量機、最大熵模型....
2、時序相關模型:
條件隨機場....
五、命名實體識別-分類算法特徵提取
The professor Colin proposed a model for NER in 1990
1) 基於單詞的特徵(word) Unigram bigram Trigram.....
-當前詞: Colin
-前/後詞:professor proposed
-前前/後後詞:the model
2) 基於stemming
proposed - > propose
3) 詞性
當前詞:名
前/後詞:名,動
前前/後後:定冠詞,名詞
4)前綴/後綴
前綴/後綴 : pro/ssor
5)當前詞的特點
當前詞的長度
是否包含大寫字母
包含多少個數字
包含了多少個大寫字符
是否包含數字
是否包含符號
是否包含特定的後綴
6)句法分析/依存分析
文本-》 提取特徵 -》1、設計特徵 2、轉化向量形式 3、特徵選擇
六、變量類型
1)cateforcal variable(沒有數值大小) onhot-encoding
-單詞相關的特徵:Apple。professor
-小學,高中,大學
-男女
2)Real variable(數值型變量) 歸一化,不做操作
-身高、體重
-氣溫
3)Ordinal variable 跟數值一樣,分類變量
-評價1星、2星、.....
-10,9,8,7.........
七、構建分類器:
方法一:根據歷史數據進行統計
from sklearn.base import BaseEstimator,TransformerMixmin
class MajorityVotingTagger(BaseEstimator,TransformerMixmin):
def fit(self,x,y):
"""
x:list of words
y:list of tags
"""
word2cnt = {}
self.tags = []
for x,t in zip(x,y):
if t not in self.tags:
self.tags.append(t)
if x in word2cut:
if t in word2cnt[x]:
word2cnt[x][t] += 1
else:
word2cnt[x][t] = 1
else:
word2cnt[x] = {t:1}
self.mjvote = {}
for k,d in word2cnt.items():
self.mjvote[k] = max(d,key=d.get)
def predict(self,X,y=None):
""" x is user input """
return [self.mjvote.get(x,'O') for x in X]
words = data['Word'].values.tolist()
tags = data['Tag'].values.tolist()
from sklearn.cross_validation import cross_val_predict
from sklearn.metrics import classification_report
pred = cross_val_predict(estimator=MajorityVotingTagger,X=words,y=tags,cv=5)
report = classification_report(y_pred=pred,y_true=tags)
print(report)
方法二:通過隨機森林
import numpy as np
def get_feature(word):
return np.array([word.istitle(),word.islower(),word.isupper(),len(word),word.isdigit(),word.isalpha(),....])
words = [get_feature(w) for w in data['Word'].value.tolist()]
tags = data['Tag'].values.tolist()
from sklearn.cross_validation import cross_val_predict
from sklearn.metrics import classification_report
from sklearn.ensemble import RandomForestClassifier
pred = cross_val_predict(RandomForestClassifier(n_estimators=20),X=words,y=tags)
report = classification_report(y_pred=pred,y_true=tags)
print(report)
def get_sentences(data):
agg_func = lambda s:[(w,p,t) for w,p,t in zip(s["Word".values.tolist(),s["POS"].values.tolist(),s['Tag'].values.tolist()])]
sentence_grouped = data.groupby("sentence").apply(agg_func)
return [s for s in sentence_grouped]
sentence = get_sentence(data)
八、獲取每個單詞的特徵
from sklearn.preprocessing import LabelEncoder
out = []
y = []
mv_tagger = MyjorityVotingTagger()
tag_encoder = LabelEncoder()
pos_encoder = LabelEncoder()
words = data["Words"].values.tolist()
tags = data['Tag'].values.tolist()
pos = data['POs'].values.tolist()
my_tagger.fit(words,tags)
tag_encoder.fit(tags)
pos_encoder.fit(pos)
for sentence in sentence:
for i in range(len(sentences)):
# w: 單詞 p:詞性 t:NER標籤
w,p,t = sentence[i][0],sentence[i][1],sentence[i][2]
if i < len(sentence) - 1:
# 如果不是句子中最後一個單詞,則可以提取出下文的特徵
mem_tag_r = tag_encoder.transform(mv_tagger.predict([sentence[i+1][0]]))[0]
true_pos_r = pos_encoder.transform([sentencer[i+1][1]])[0]
else:
mem_tag_r = tag_encoder.transform(['O'])[0]
true_pos_r = pos_encoder.transform(['.'])[0]
if i > 0:
# 如果不是句子中的第一個單詞,則可以提取上文的特徵
mem_tag_1 = tag_encoder.transform(mv_tagger.predict([sentence[i-1][0]]))[0]
true_pos_1 = pos_encoder.transform([sentence[i-1][1]])[0]
else:
mem_tag_1 = tag_encoder.transform([')'])[0]
true_pos_1 = pos_encoder.transform(['.'])[0]
# 特徵整合
out.append(np.array([w.istitle(),
w.islower(),
w.isuppper(),
len(w),
w.isdigit(),
w.isalpha(),
tag_encoder.transform(mv_tagger.predict([w]))[0],
pos_encoder.transform([p])[0],
mem_tag_r,
true_pos_r,
mem_tag_1,
true_pos_1]))
# 標籤
y.append(t)
from sklearn.cross_validation import cross_val_predict
from sklearn.metrics import classification_report
pred = cross_val_predict(RandomForestClassifier(n_estimators=20),x=out,y=y,cv=5)
report = classification_report(y_pred=pred,y_true=y)
print(report)
九、通過CRF命名實體識別
def word2features(sentence,i):
"""
sentence: input sentence
i: index of word
"""
word = sentence[i][0]
postag = sentence[i][1]
features = {
'bias':1.0,
'word.lower()':word.lower(),
'word[-3:]':word[-3:],
'word[-2:]':word[-2:],
'word.isupper()':word.isupper(),
'word.istitle()':word.istitle(),
'word.isdigit()':word.isdigit(),
'postag':postag,
'postag[:2]':postag[:2],
}
if i > 0:
word1 = sentence[i-1][0]
postag1 = sentence[i-1][1]
features.update({
'-1:word.lower()':word1.lower(),
'-1:word.istitle()':word1.istitle(),
'-1:word.isupper()':word1.isupper(),
'-1:postag':postag1,
'-1:postag[:2]':postag1[:2],
})
else:
features['BOS'] = True
if i < len(sentence)-1:
word1 = sentence[i+1][0]
postag1 = sentence[i+1][1]
features.update([
'+1:word.lower()':word1.lower(),
'+1:word.istitle()':word1.istitle(),
'+1:word.isupper()':word1.isupper(),
'+1:postag':postag1,
'+1:postag[:2]':postag2
])
else:
features['EOS'] = True
def sentence2features(sentence):
return [word2features(sentence,i) for i in range(len(sentence))]
def sentence2labels(sentences):
return [label for token,postag,label in sent]
X = [sentence2features(s) for s in sentences]
y = [sentence2labels(s) for s in sentences]
from sklearn_crfsuite import CRF
crf = CRF(algorithm='lbfgs',c1=0.1,c2=0.1,max_iterations=100)
from sklearn.cross_validation import cross_val_predict
from sklearn.crfsuite.metrics import flat_classification_report
pred = cross_val_predict(estimator=crf,X=x,y=y,cv=5)
report = flat_classification_report(y_pred=pred,y_true=y)
print(report)