一、命名实体识别简单概要
按照类型标记每一个名词:对句子名词进行分类
我今天(时间)要去北京(地点)参加面试
张三(人名)出生于上海(地名),清华大学(组织)毕业后去百度(组织)任职。
命名实体识别: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)