美文网首页工作生活
探索上下文语境

探索上下文语境

作者: 青椒rose炒饭 | 来源:发表于2019-07-04 19:49 被阅读0次

前面标注器有基于默认标注器,正则表达式标注器以及查询标注器等等。在本章分类的基础上构建一个单词分类器。借助于上下文语境,这也可以是单词词性的一个特征。例如:标注词fly,如果知道它前面的词是“a”将使我们能够确定它是一个名词,而不是一个动词。

  • 特征提取:正则表达式标注器主要是识别单词的后缀,这也可以作为单词词性的特征,特征就需要提取单词的后几个字母,以及在句子中的前一个单词。
  • 数据:(特征集,词性)构成个链表,只要能实现这个形式的就行具体也没有特殊的要求。

直接上代码吧。

from nltk.corpus import brown
import nltk

#特征提取函数
def pos_feature(sent,i):
    '''
    :param sent: 由多个单词元组(单词,词性)组成的list链表
    :param i: 获取第i个单词的词性特征
    :return: 特征集
    '''
    features = {
        "suffix(1)":sent[i][0][-1:],
        "suffix(2)":sent[i][0][-2:],
        "suffix(3)":sent[i][0][-3:]
    }
    if i == 0:
        features["pre_word"] = '<START>'
    else:
        features["pre_word"] = sent[i-1][0]
    return features
#获取每个单词的词性特征集,以及词性构成列表。
# 每个句子是由多个单词元组(单词,词性)组成的list链表
feature_words = [
    (pos_feature(sent,i),sent[i][1])
    #获取所有句子
    for sent in brown.tagged_sents(categories="news")
    #计算句子中的单词个数,逐个遍历
    for i in range(len(sent))
]
#此语句是我用于查找错误的
print(feature_words[1])
#划分数据
train_set,test_set = feature_words[1000:],feature_words[:1000]
#词性分类器
classfier = nltk.NaiveBayesClassifier.train(train_set)
#分类books这个单词
print(classfier.classify(pos_feature(["books"],0)))
#评估分类器准确度
print(nltk.classify.accuracy(classfier,test_set))
运行结果

序列分类

序列分类模型用来为一个句子中的所有词共同选择词性标签。其中一种序列分类器称为连续分类或贪婪序列分类,是为第一个找到最有可能的标签,然后根据第一个的标签帮助找到下一个的最佳标签,如此重复,直到所有输入都贴上标签为止。体现在模型上我个人感觉就是训练数据不一样吧,其他的貌似没有什么区别。下面是序列分类器(连续分类器或者贪婪分类器)书上提供的代码。

import nltk
#特征提取函数
def pos_feature(sentence,i,history):
    #特征集首先是提取单词后缀
    features = {
        "suffix(1)":sentence[i][-1:],
        "suffix(2)":sentence[i][-2:],
        "suffix(3)":sentence[i][-3:]
    }
    #提取单词的前一个单词和标签作为特征
    if i == 0:
        features["pre-word"] = "<start>"
        features["pre-tag"] = "<start>"
    else:
        features["pre-word"] = sentence[i-1]
        features["pre-tag"] = history[i-1]
    return features

#连续词性标注器(实际是分类)
class ConsecutivePosTagger(nltk.TaggerI):
    def __init__(self,train_sents):
        #下面这个训练集的获取不是很明白为啥一会去标签不去标签的,
        #直接在tagged_sents里面直接就包含了几乎所有需要的信息了呀
        train_set = []
        for tagged_sent in train_sents:
            untagged_sent = nltk.tag.untag(tagged_sent)
            history = []
            for i ,(word,tag) in enumerate(tagged_sent):
                featureset = pos_feature(untagged_sent,i,history)
                train_set.append((featureset,tag))
                history.append(tag)
        #输出一条训练数据查看
        print("第一条训练数据:",train_set[1])
        #训练模型
        self.classifier = nltk.NaiveBayesClassifier.train(train_set)

    #该类下的标注方法
    def tag(self,sentence):
        history = []
        for i,word in enumerate(sentence):
            featureset = pos_feature(sentence,i,history)
            tag = self.classifier.classify(featureset)
            history.append(tag)
        return zip(sentence,history)

tagged_sents = nltk.corpus.brown.tagged_sents(categories='news')
size = int(len(tagged_sents) * 0.1)
train_sents, test_sents = tagged_sents[size:], tagged_sents[:size]
#创建该类的对象
tagger = ConsecutivePosTagger(train_sents)
print(tagger.evaluate(test_sents))

写完这个代码的时候发现了序列分类,参照前一个输入的词性标注当前单词词性体现在哪里。体现在该类的标注方法tag()里面,里面的特征提取也是和训练数据的特征一样。介于朴素贝叶斯分类模型没有学也不好解释。

其他序列分类方法

上面这种方法的缺点是只参考前一个单词,而且一旦确定了单词的标签无法更改。这个问题需要采用转型策略。另一种方案是为所有可能的序列打分,选择总得分最高的序列。隐马尔可夫模型就是采用这种方法。

相关文章

网友评论

    本文标题:探索上下文语境

    本文链接:https://www.haomeiwen.com/subject/bdcrhctx.html