天天看点

自然语言处理(1)——词汇标注

如何进行词汇标注呢?首先进行数据预处理,例如如果给定的是句子,先要对句子进行分割;最简单的标注器,可以给定词汇使用得最频繁的词性作为标注器中该词汇的词性,但是由于词汇存在二义性,使得这种标注准确度受限,通过上下文语境,可以在一定程度上解决这个问题,可以采用N-gram标注器,此外,Brill标注器具有修正功能。

为了使python的中文注释正确,必须在开头加上一句代码

# -*- coding: utf-8 -*-
# 这个编码转换必须放在第一行,否则中文注释会报错
           

将词汇按它们的词性(parts-of-speech,POS)分类以及相应的标注它们的过程被称为词性标注(part-of-speech tagging, POS tagging)。

利用NLTP,可以比较方便地进行词性标注。

为了对词汇进行标注,我们需要把句子进行分割,之后可以使用nltk的词性标注器进行标注。

# 使用词性标注器
text=nltk.word_tokenize("And now for something completely different")
nltk.pos_tag(text)
           

NLTK中对数据进行预处理

# str2tuple()从表示一个已标注的标识符的标准字符串创建一个这样的特殊元组
tagged_token=nltk.tag.str2tuple('fly/NN')

# text.similar()方法为一个词w 找出所有上下文w1ww2,然后找出所有出现在相同上下文中的词w',即w1w'w2
text=nltk.Text(word.lower() for word in nltk.corpus.brown.words())
text.similar('woman')

# 读取已标注语料库
# 常用语料库 brown, nps_chat, conll2000, treebank, 
nltk.corpus.brown.tagged_words()

from nltk.corpus import brown 
brown_news_tagged=brown.tagged_words(categories='news')
tag_fd=nltk.FreqDist(tag for (word, tag) in brown_news_tagged)
tag_fd.keys()[:5] 

# 找出最频繁的名词标记
def findtags(tag_prefix, tagged_text):
	cfd=nltk.ConditionalFreqDist((tag,word) for (word,tag) in tagged_text
		if tag.startswith(tag_prefix))
	return dict((tag, cfd[tag].keys()[:5]) for tag in cfd.conditions())
	
# 查看跟在ofen后的词汇
brown_learned_text=nltk.corpus.brown.words(categories='learned')
sorted(set(b for(a,b) in nltk.bigrams(brown_learned_text) if a=='often'))

# 使用POS标记寻找三词短语
from nltk.corpus import brown 
def process(sentence):
	for (w1,t1),(w2,t2),(w3,t3) in nltk.trigrams(sentence):
		if (t1.startswith('V') and t2=='TO' and t3.startswith('V')):
			print w1,w2,w3
			
# 查看标记模糊的词
brown_news_tagged = brown.tagged_words(categories='news')
data=nltk.ConditionalFreqDist((word.lower(),tag) for (word,tag) in brown_news_tagged)
for word in data.conditions():
	if len(data[word])>=3:
		tags=data[word].keys()
		print word,' '.join(tags)
		
'''
使用Python字典映射词及其属性 pos['键']='值',字典不是序列,键没有固定顺序,
定义字典:pos={'A':'a','B':'b'}或pos=dict(A='a',B='b')
使用for循环遍历字典中的键:for word in sorte(dict)
字典的常用方法。keys(), values(), items(): for key,val in sorted(dict.items()),update(), append()
字典的键必须是不可改变的类型,如字符串或元组
'''

# 递增的更新字典
counts=nltk.defaultdict(int)
from nltk.corpus import brown 
for (word,tag) in brown.tagged_words(categories='news'):
	counts[tag]+=1
from operator import itemgetter	
sorted(counts.items(), key=itemgetter(1),reverse=True) #按照值递减排序

# 如果经常用到反向查找,可以建立一个值到键的字典
           

标注器   二义性限制了标注器的上限,上下文可以解决歧义问题

N-gram标注 利用了上下文中的词作为特征,有点像开环的,没有反馈

Brill标注 归纳标注法 猜测每个词的标注,然后返回和修复错误,有点像闭环,有返回,不对修正错误

# NLTK数据加载
from nltk.corpus. import brown
brown_tagged_sents=brown.tagged_sents(categories='news') #加载已标注句子
brown_sents=brown.sents(categories='news')	#加载句子

# 正则表达式标注器
patterns=[
	(r'.*ing$','VBG'),
	(r'.*ed&','VBD'),
	(r'.*es$','VBZ'),
	(r'.*ould$', 'MD'),
	(r'.*\'s$', 'NN$'),
	(r'.*s$', 'NNS'),
	(r'^-?[0-9]+(.[0-9]+)?$', 'CD'),
	(r'.*', 'NN')
	]
regexp_tagger=nltk.RegexpTagger(patterns)
regexp_tagger.tag(brown_sents[3])

#查询标注器
fd = nltk.FreqDist(brown.words(categories='news')) #词汇的频率统计
cfd = nltk.ConditionalFreqDist(brown.tagged_words(categories='news')) #词汇的条件分布,该词的词性的统计
most_freq_words = fd.keys()[:100] #前100个高频词
likely_tags = dict((word, cfd[word].max()) for word in most_freq_words) #前100个高频词,以及高频词的最可能的词性标注
baseline_tagger = nltk.UnigramTagger(model=likely_tags) 
# 回退
baseline_tagger = nltk.UnigramTagger(model=likely_tags, backoff=nltk.DefaultTagger('NN'))

# N-gram标注
from nltk.corpus import brown
brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories='news')
unigram_tagger = nltk.UnigramTagger(brown_tagged_sents) # 通过已经标注的句子训练一个一元标注器
unigram_tagger.tag(brown_sents[2007]) # 使用这个一元标注器标注未进行标注的句子

bigram_tagger.evaluate(test_sents) # 用于评估

# 组合标注器:解决精度和覆盖范围的一个权衡办法
t0=nltk.DefaultTagger('NN')
t1=nltk.UnigramTagger(train_sents,backoff=t0)
t2=nltk.BigramTagger(train_sents,backoff=t1)
t2.evaluate(test_sents) # 先调用t2的bigram标注器标注,找不到就尝试t1,再不行就用默认标注器t0

nltk.BigramTagger(sents,cutoff=2,backoff=t1) # 丢弃只出现一两次的上下文

# 存储标注器给以后使用
from cPickle import dump
output=open('t2.pkl','wb')
dump(t2,output,-1) #将t2标注器写到output,可以用方法的形式 p=cPickle.dump(t2)
output.close()

from cPickle import load
input=open('t2.pkl','rb')
tagger=load(input)

# brill标注器演示 基于转换的标注学习一系列“改变标记s 为标记t 在上下文c 中”形式的修复规则
nltk.tag.brill.demo()
           

一直以来都没有写博客的习惯,从今天开始,要改变自己。

继续阅读