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)整理地理位置词库。在识别时,先通过词库匹配,再采用模型进行发现。


  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python自然语言处理实战核心技术与算法》是一本深入介绍自然语言处理领域核心技术和算法的图书。书中首先从自然语言处理的基本概念和原理入手,介绍了自然语言处理的基本任务和应用场景。随后详细介绍了使用Python编程语言进行自然语言处理的相关工具和库,包括NLTK、spaCy和gensim等。读者将学习如何使用这些工具处理文本数据,进行分词、词性标注命名实体识别等常见任务。 在核心技术方面,书中深入讲解了词向量表示、文本分类、情感分析、文本生成等自然语言处理领域的重要概念和方法。读者将学习到如何用Python实现这些技术,并将其运用到实际的文本数据中。此外,书中还介绍了一些经典的自然语言处理算法,例如HMM和CRF,在讲解这些算法的同时,也教会了读者如何使用Python来实现它们。 除此之外,书中还结合了一些实际的自然语言处理案例,通过这些案例的讲解,读者可以更好地理解自然语言处理的实际应用以及如何运用Python来解决具体的问题。最后,书中还介绍了一些自然语言处理领域的前沿技术和研究方向,为读者提供了未来深入学习的方向。 总之,《Python自然语言处理实战核心技术与算法》以通俗易懂的语言系统地介绍了自然语言处理的基础知识、核心技术和算法,适合有一定Python编程基础的读者阅读。通过学习本书,读者能够全面了解自然语言处理的前沿技术,掌握用Python来解决实际问题的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值