python自然语言处理 | 学习分类文本

  • 本章解决问题
  1. 我们怎样才能识别语言数据中能明显用于对其分类的特征
  2. 我们怎样才能构建语言模型,用于自动执行语言处理任务?
  3. 从这些模型中我们可以学到哪些关于语言的知识

这里写目录标题

  • 1 有监督分类
    • 1.1 性别鉴定
    • 1.2 选择正确的特征
    • 1.3 文档分类
    • 1.4 词性标注
    • 1.5 探索上下文语境
    • 1.6 序列分类
    • 1.7 其他序列分类方法
  • 2 有监督分类的更多例子
    • 2.1 句子分割
    • 2.2 识别对话行为类型
    • 2.3 识别文字蕴含
    • 2.4 扩展到大型数据集
  • 3 评估
    • 3.1 测试集
    • 3.2 准确度
    • 3.3 精确度和召回率
    • 3.4 混淆矩阵
    • 3.5 交叉验证
  • 4 决策树
  • 5 朴素贝叶斯分类器
  • 6 最大熵分类器
    • 6.1 最大熵模型
    • 6.2 熵的最大化
    • 6.3 生成式分类器对比条件式分类器
  • 7 为语言模式建模
  • 8 小结
  • 9 练习

1 有监督分类

分类是为给定的输入选择正确的类标签的任务。在基本的分类任务中,每个输入被认为是与所有其它输入隔离的,并且标签集是预先定义的。这里是分类任务的一些例子:

  1. 判断一封电子邮件是否是垃圾邮件。
  2. 从一个固定的主题领域列表中,如“体育”、“技术”和“政治”,决定新闻报道的主题是什么。
  3. 决定词 bank 给定的出现是用来指河的坡岸、一个金融机构、向一边倾斜的动作还是在金融机构里的存储行为。

有监督分类:一个分类称为有监督的,如果它的建立基于训练语料的每个输入包含正确标签。有监督分类使用的框架图如1.1所示。

python自然语言处理 | 学习分类文本_第1张图片

  • a:在训练过程中,特征提取器用来将每一个输入值转换为特征集。这些特征集捕捉每个输入中应被用于对其分类的基本信息。特征集与标签的配对被送入机器学习算法,生成模型
  • b:在预测过程中,相同的特征提取器被用来将未见过的输入转换为特征集。之后,这些特征集被送入模型产生预测标签。

1.1 性别鉴定

在4中,我们看到,男性和女性的名字有一些鲜明的特点。以a,e和i结尾的很可能是女性,而以k,o,r,s和t结尾的很可能是男性。让我们建立一个分类器更精确地模拟这些差异。下面用性别鉴定的分类来示例。

  1. 创建一个分类器的第一步是决定输入的什么样的特征是相关的,以及如何为那些特征编码。

在这个例子中,我们一开始只是寻找一个给定的名称的最后一个字母。以下特征提取器函数建立一个字典,包含有关给定名称的相关信息:

"""
1. 创建一个分类器的第一步是决定输入的什么样的特征是相关的,以及如何为那些特征编码。
这里的特征是以a,e和i结尾的很可能是女性,而以k,o,r,s和t结尾的很可能是男性
"""
# 定义了一个特征提取器
def gender_features(word):
    return {"last_letter": word[-1]}
gender_features("Shrek")

"""2 准备一个例子和对应类标签的列表"""
from nltk.corpus import names
labeled_names = ([(name, "male") for name in names.words("male.txt")]) + \
[(name, "female") for name in names.words("female.txt")]

import random
random.shuffle(labeled_names)
"""
3 使用特征提取器处理names数据,并划分特征集的结果链表为一个训练集和一个测试集。
训练集用于训练一个新的“朴素贝叶斯”分类器。
"""
import nltk
featuresets = [(gender_features(n), gender) for (n, gender) in labeled_names]  # features = (特征,标签)
train_set, test_set = featuresets[500:], featuresets[:500]  # 划分训练集和测试集
classifier = nltk.NaiveBayesClassifier.train(train_set)   # 通过训练得到模型
"""4 使用模型"""
print(classifier.classify(gender_features("Neo")))
print(classifier.classify(gender_features("Trinity")))

"""5 检查分类器,确定哪些特征对于区分名字的性别是最有效的"""
classifier.show_most_informative_features(5)
print(nltk.classify.accuracy(classifier, test_set))  

在处理大型语料库时,构建一个包含每一个实例的特征的单独的列表会使用大量的内存。在这些情况下,使用函数`nltk.classify.apply_features’,返回一个行为像一个列表而不会在内存存储所有特征集的对象。如下:

from nltk.classify import apply_features
train_set = apply_features(gender_features, labeled_names[500:])  # 训练集
test_set = apply_features(gender_features, labeled_names[:500])   # 测试集

1.2 选择正确的特征

特征提取通过反复试验和错误的过程建立的,由哪些信息是与问题相关的直觉指引的。它通常以“厨房水槽”的方法开始,包括你能想到的所有特征,然后检查哪些特征是实际有用的。我们在1.2中对名字性别特征采取这种做法。

def gender_features2(name):
    features = {}
    features["first_letter"] = name[0].lower()
    features["last_letter"] = name[-1].lower()
    for letter in "abcdefghijklmnopqrstuvwxyz":
        features["count({})".format(letter)] = name.lower().count(letter)
        features["has({})".format(letter)] = (letter in name.lower())
    return features

然而,你要用于一个给定的学习算法的特征的数目是有限的——如果你提供太多的特征,那么该算法将高度依赖你的训练数据的特性,而一般化到新的例子的效果不会很好。这个问题被称为过拟合,当运作在小训练集上时尤其会有问题。

# 考虑太多特征导致这个系统的精度比只考虑每个名字最后一个字母的分类器的精度低约1%
featuresets = [(gender_features2(n), gender) for (n, gender) in labeled_names]
train_set, test_set = featuresets[500:], featuresets[:500]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, test_set))         # 书上这样说的低1%,可是这里由之前的0.762--> 0.766 ,优化了?  不过太多特征,降低处理效率

一旦初始特征集被选定,完善特征集的一个非常有成效的方法是错误分析。
python自然语言处理 | 学习分类文本_第2张图片

"""首先,我们选择一个开发集,包含用于创建模型的语料数据。然后将这种开发集分为训练集和开发测试集。"""
train_names = labeled_names[1500:]  # 训练集用于训练模型
devtest_names = labeled_names[500:1500]  # 开发测试集用于进行错误分析
test_names = labeled_names[:500]  # 测试集是用于测试
"""已经将语料分为适当的数据集,我们使用训练集训练一个模型,然后在开发测试集上运行"""
train_set = [(gender_features(n), gender) for (n, gender) in train_names]
devtest_set = [(gender_features(n), gender) for (n, gender) in devtest_names]
test_set = [(gender_features(n), gender) for (n, gender) in test_names]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, devtest_set)) 
"""使用开发测试集,我们可以生成一个分类器预测名字性别时的错误列表"""
errors = []
for (name, tag) in devtest_names:
    guess = classifier.classify(gender_features(name))
    if guess != tag:
        errors.append((tag, guess, name))
"""
然后,可以检查个别错误案例,在那里该模型预测了错误的标签,
尝试确定什么额外信息将使其能够作出正确的决定(或者现有的哪部分信息导致其做出错误的决定)。
然后可以相应的调整特征集
"""
count = 0
for (tag, guess, name) in sorted(errors):
    print("correct={:<8} guess={:<8s} name={:<30}".format(tag, guess, name))
    count += 1
    if count >10:
        break

明确指出一些多个字母的后缀可以指示名字性别。例如,yn结尾的名字显示以女性为主,尽管事实上,n结尾的名字往往是男性;以ch结尾的名字通常是男性,尽管以h结尾的名字倾向于是女性。因此,调整我们的特征提取器包括两个字母后缀的特征。

def gender_features(word):
    return {"suffix1": word[-1:],
           "suffix2": word[-2:]}
"""使用新的特征提取器重建分类器,提高1个百分点,0.763 --> 0.773"""
train_set = [(gender_features(n), gender) for (n, gender) in train_names]
devtest_set = [(gender_features(n), gender) for (n, gender) in devtest_names]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, devtest_set)) 

1.3 文档分类

使用这些语料库,我们可以建立分类器,自动给新文档添加适当的类别标签。

首先,我们构造一个标记了相应类别的文档清单。对于这个例子,我们选择电影评论语料库,将每个评论归类为正面或负面。

"构造一个标记了相应类别的文档清单"
from nltk.corpus import movie_reviews
documents = [(list(movie_reviews.words(fileid)), category)
                         for category in movie_reviews.categories()
                         for fileid in movie_reviews.fileids(category)]
random.shuffle(documents)

接下来,我们为文档定义一个特征提取器,这样分类器就会知道哪些方面的数据应注意(1.4)。对于文档主题识别,我们可以为每个词定义一个特性表示该文档是否包含这个词。为了限制分类器需要处理的特征的数目,我们一开始构建一个整个语料库中前2000个最频繁词的列表。然后,定义一个特征提取器,简单地检查这些词是否在一个给定的文档中。

"构建一个整个语料库中前2000个最频繁词的列表"
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = list(all_words)[:2000]

def document_features(document):
    document_words = set(document)
    features = {}
    for word in word_features:
        features["contains({})".format(word)] = (word in document_words)
    return features

已经定义了我们的特征提取器,可以用它来训练一个分类器,为新的电影评论加标签。

"""训练分类器"""
featuresets = [(document_features(d), c) for (d,c) in documents]
train_set, test_set = featuresets[100:], featuresets[:100]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, test_set))  # 0.83,还好?

1.4 词性标注

训练一个分类器来算出哪个后缀最有信息量

from nltk.corpus import brown

suffix_fdist = nltk.FreqDist()
# 获得后缀的计数的字典
for word in brown.words():
    word = word.lower()
    suffix_fdist[word[-1:]] += 1
    suffix_fdist[word[-2:]] += 1
    suffix_fdist[word[-3:]] += 1
common_suffixes = [suffix for (suffix, count) in suffix_fdist.most_common(100)]
print(common_suffixes)

"""定义一个特征提取器函数,检查给定的单词的这些后缀"""
def pos_features(word):
    features = {}
    for suffix in common_suffixes:
        features["endswith({})".format(suffix)] = word.lower().endswith(suffix)
    return features

特征提取函数的行为就像有色眼镜一样,强调我们的数据中的某些属性(颜色),并使其无法看到其他属性。分类器在决定如何标记输入时,将完全依赖它们强调的属性。在这种情况下,分类器将只基于一个给定的词拥有(如果有)哪个常见后缀的信息来做决定。

"""用它来训练一个新的“决策树”标记分类器"""
tagged_words = brown.tagged_words(categories='news')
featuresets = [(pos_features(n), g) for (n,g) in tagged_words]
size = int(len(featuresets) * 0.1)
train_set, test_set = featuresets[size:], featuresets[:size]
classifier = nltk.DecisionTreeClassifier.train(train_set)
nltk.classify.accuracy(classifier, test_set)
classifier.classify(pos_features("cats"))
# 决策树模型的一个很好的性质是它们往往很容易解释——我们甚至可以指示NLTK将它们以伪代码形式输出:
print(classifier.pseudocode(depth = 4))
"""
1. 可以看到分类器一开始检查一个词是否以逗号结尾——如果是,它会得到一个特别的标记","。
2. 接下来,分类器检查词是否以"the"尾,这种情况它几乎肯定是一个限定词。这个“后缀”被决策树早早使用是因为词"the"太常见。
3. 分类器继续检查词是否以"s"结尾。如果是,那么它极有可能得到动词标记VBZ(除非它是这个词"is",它有特殊标记BEZ).
4. 如果不是,那么它往往是名词(除非它是标点符号“.”)。
5. 实际的分类器包含这里显示的if-then语句下面进一步的嵌套,参数depth=4 只显示决策树的顶端部分。
"""

1.5 探索上下文语境

通过增加特征提取函数,我们可以修改这个词性标注器来利用各种词内部的其他特征,例如词长、它所包含的音节数或者它的前缀。
然而,只要特征提取器仅仅看着目标词,我们就没法添加依赖词出现的上下文语境特征

为了采取基于词的上下文的特征,我们必须修改以前为我们的特征提取器定义的模式。不是只传递已标注的词,我们将传递整个(未标注的)句子,以及目标词的索引

"""使用依赖上下文的特征提取器定义一个词性标记分类器。"""
def pos_features(sentence, i):
    features = {"suffix(1)": sentence[i][-1:],
               "suffix(2)": sentence[i][-2:],
               "suffix(3)": sentence[i][-3:]}
    if i == 0:
        features["prev-word"] = ""
    else:
        features["prev-word"] = sentence[i - 1]
    return features

pos_features(brown.sents()[0],8)
tagged_sents = brown.tagged_sents(categories='news')
featuresets =[]
for tagged_sent in tagged_sents:
    untagged_sent= nltk.tag.untag(tagged_sent)
    for i,(word,tag) in enumerate(tagged_sent):
        featuresets.append((pos_features(untagged_sent,i), tag))

size = int(len( featuresets)*0.1)
train_set,test_set = featuresets[size:],featuresets[:size]
classifier = nltk.NaiveBayesClassifier.train(train_set)
nltk.classify.accuracy(classifier,test_set)  # 加入句子后,利用上下文特征提高了我们的词性标注器的准确性。

1.6 序列分类

  1. 为了捕捉相关的分类任务之间的依赖关系,我们可以使用联合分类器模型,收集有关输入,选择适当的标签。
  2. 在词性标注的例子中,各种不同的序列分类器模型可以被用来为一个给定的句子中的所有的词共同选择词性标签。

一种序列分类器策略,称为连续分类或贪婪序列分类,是为第一个输入找到最有可能的类标签,然后使用这个问题的答案帮助找到下一个输入的最佳的标签。这个过程可以不断重复直到所有的输入都被贴上标签。

在下面例子中演示了这一策略。

  • 首先,我们必须扩展我们的特征提取函数使其具有参数history,它提供一个我们到目前为止已经为句子预测的标记的列表。
  • history中的每个标记对应sentence中的一个词。但是请注意,history将只包含我们已经归类的词的标记,也就是目标词左侧的词。
  • 因此,虽然是有可能查看目标词右边的词的某些特征,但查看那些词的标记是不可能的(因为我们还未产生它们)。
# sentence:上下文
# i:词语后缀
# history:目标词左侧的词的标记
def pos_features(sentence, i, history): 
    features = {"suffix(1)": sentence[i][-1:],
                 "suffix(2)": sentence[i][-2:],
                 "suffix(3)": sentence[i][-3:]}
    if i == 0:
        features["prev-word"] = ""
        features["prev-tag"] = ""
    else:
        features["prev-word"] = sentence[i - 1]
        features["prev-tag"] = history[i - 1]
    return features

class ConsecutivePosTagger(nltk.TaggerI): 

    def __init__(self, train_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_features(untagged_sent, i, history)
                train_set.append( (featureset, tag) )
                history.append(tag)
        self.classifier = nltk.NaiveBayesClassifier.train(train_set)

    def tag(self, sentence):
        history = []
        for i, word in enumerate(sentence):
            featureset = pos_features(sentence, i, history)
            tag = self.classifier.classify(featureset)
            history.append(tag)
        return zip(sentence, history)

tagged_sents = 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))

1.7 其他序列分类方法

转型联合分类的工作原理是为输入的标签创建一个初始值,然后反复提炼那个值,尝试修复相关输入之间的不一致。

  • Brill标注器中描述的,是这种策略的一个很好的例子。

另一种方案是为词性标记所有可能的序列打分,选择总得分最高的序列。

  • 隐马尔可夫模型
  • 最大熵马尔可夫模型
  • 线性链条件随机场模型

2 有监督分类的更多例子

2.1 句子分割

句子分割可以看作是一个标点符号的分类任务:每当我们遇到一个可能会结束一个句子的符号,如句号或问号,我们必须决定它是否终止了当前句子。

"""1 获得一些已被分割成句子的数据,将它转换成一种适合提取特征的形式"""
sents = nltk.corpus.treebank_raw.sents()
tokens = [] 
boundaries = set()
offset = 0
for sent in sents:
    tokens.extend(sent)  # tokens是单独句子标识符的合并列表
    offset += len(sent)
    boundaries.add(offset - 1)  # boundaries是一个包含所有句子边界词符索引的集合
"""2 需要指定用于决定标点是否表示句子边界的数据特征"""
def punct_features(tokens, i):
    return {'next-word-capitalized': tokens[i+1][0].isupper(),
             'prev-word': tokens[i-1].lower(),
             'punct': tokens[i],
             'prev-word-is-one-char': len(tokens[i-1]) == 1}
"""
3 基于这一特征提取器,我们可以通过选择所有的标点符号创建一个加标签的特征集的列表,然后标注它们是否是边界标识符
"""
featuresets = [(punct_features(tokens, i), (i in boundaries))
                for i in range(1, len(tokens)-1)
                if tokens[i] in '.?!']
"""
4 使用这些特征集,我们可以训练和评估一个标点符号分类器
"""
size = int(len(featuresets) * 0.1)
train_set, test_set = featuresets[size:], featuresets[:size]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, test_set)) # 0.936026936026936

使用这种分类器进行断句,我们只需检查每个标点符号,看它是否是作为一个边界标识符;在边界标识符处分割词列表。原理实现如下:

def segment_sentences(words):
    start = 0
    sents = []
    for i, word in enumerate(words):
        if word in '.?!' and classifier.classify(punct_features(words, i)) == True:
            sents.append(words[start:i+1])
            start = i+1
    if start < len(words):
        sents.append(words[start:])
    return sents

2.2 识别对话行为类型

NPS聊天语料库,在1中的展示过,包括超过10,000个来自即时消息会话的帖子。这些帖子都已经被贴上15 种对话行为类型中的一种标签,例如“陈述”,“情感”,“yn问题”和“Continuer”。

  • 因此,我们可以利用这些数据建立一个分类器,识别新的即时消息帖子的对话行为类型。
"""
1 第一步是提取基本的消息数据。我们将调用xml_posts()来得到一个数据结构,表示每个帖子的XML注释:
"""
posts = nltk.corpus.nps_chat.xml_posts()[:10000]
"""
2 第二步 我们将定义一个简单的特征提取器,检查帖子包含什么词
"""
def dialogue_act_features(post):
    features = {}
    for word in nltk.word_tokenize(post):
        features['contains({})'.format(word.lower())] = True
    return features
"""
3 最后,我们通过为每个帖子提取特征(使用post.get(‘class’)获得一个帖子的对话行为类型)构造训练和测试数据,并创建一个新的分类器
"""
featuresets = [(dialogue_act_features(post.text), post.get('class'))
               for post in posts]
size = int(len(featuresets) * 0.1)
train_set, test_set = featuresets[size:], featuresets[:size]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier, test_set)) # 0.667

2.3 识别文字蕴含

  1. 识别文字蕴含(RTE)是判断文本T的一个给定片段是否蕴含着另一个叫做“假设”的文本(已经在5讨论过)。
  2. 应当强调,文字和假设之间的关系并不一定是逻辑蕴涵,而是一个人是否会得出结论:文本提供了合理的证据证明假设是真实的。
识别方法:
1. 在我们的RTE 特征探测器(2.2)中,我们让词(即词类型)作为信息的代理,我们的**特征计数词重叠的程度和假设中有而文本中没有的词的程度**(由hyp_extra()方法获取)。
2. 不是所有的词都是同样重要的——命名实体,如人、组织和地方的名称,可能会更为重要,这促使我们分别为words和nes(命名实体)提取不同的信息。3. 此外,一些高频虚词作为“停用词”被过滤掉。
def rte_features(rtepair):
    extractor = nltk.RTEFeatureExtractor(rtepair)
    features = {}
    features['word_overlap'] = len(extractor.overlap('word'))
    features['word_hyp_extra'] = len(extractor.hyp_extra('word'))
    features['ne_overlap'] = len(extractor.overlap('ne'))
    features['ne_hyp_extra'] = len(extractor.hyp_extra('ne'))
    return features
# 说明这些特征的内容,我们检查前面显示的文本/假设对34的一些属性
rtepair = nltk.corpus.rte.pairs(['rte3_dev.xml'])[33]
extractor = nltk.RTEFeatureExtractor(rtepair)
print(extractor.text_words)
print(extractor.hyp_words)
print(extractor.overlap('word'))
print(extractor.overlap('ne'))
print(extractor.hyp_extra('word'))

# 这些特征表明假设中所有重要的词都包含在文本中,因此有一些证据支持标记这个为True。
# nltk.classify.rte_classify模块使用这些方法在合并的RTE测试数据上取得了刚刚超过58%的准确率。这个数字并不是很令人印象深刻的,还需要大量的努力,更多的语言学处理,才能达到更好的结果。

2.4 扩展到大型数据集

安装其他软件包

3 评估

3.1 测试集

# 从一个反映单一的文体(如新闻)的数据源随机分配句子,创建训练集和测试集
import random
from nltk.corpus import brown
tagged_sents = list(brown.tagged_sents(categories='news'))
random.shuffle(tagged_sents)
size = int(len(tagged_sents) * 0.1)
train_set, test_set = tagged_sents[size:], tagged_sents[:size]

缺陷:

  1. 训练集和测试集均取自同一文体,所以我们不能相信评估结果可以推广到其他文体
  2. 调用random.shuffle(),测试集中包含来自训练使用过的相同的文档的句子
# 稍好的做法是确保训练集和测试集来自不同的文件
file_ids = brown.fileids(categories='news')
size = int(len(file_ids) * 0.1)
train_set = brown.tagged_sents(file_ids[size:])
test_set = brown.tagged_sents(file_ids[:size])
# 要执行更令人信服的评估,可以从与训练集中文档联系更少的文档中获取测试集
train_set = brown.tagged_sents(categories='news')
test_set = brown.tagged_sents(categories='fiction')

3.2 准确度

准确度:测量测试集上分类器正确标注的输入的比例

posts = nltk.corpus.nps_chat.xml_posts()[:10000]

def dialogue_act_features(post):
    features = {}
    for word in nltk.word_tokenize(post):
        features['contains({})'.format(word.lower())] = True
    return features

featuresets = [(dialogue_act_features(post.text), post.get('class'))
               for post in posts]

size = int(len(featuresets) * 0.1)
train_set, test_set = featuresets[size:], featuresets[:size]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print('Accuracy: {:4.2f}'.format(nltk.classify.accuracy(classifier, test_set))) 

3.3 精确度和召回率

真阳性是相关项目中我们正确识别为相关的。
真阴性是不相关项目中我们正确识别为不相关的。
假阳性(或I 型错误)是不相关项目中我们错误识别为相关的。
假阴性(或II型错误)是相关项目中我们错误识别为不相关的。
  • 精确度,表示我们发现的项目中有多少是相关的,TP/(TP+FP)。
  • 召回率,表示相关的项目中我们发现了多少,TP/(TP+FN)。
  • F-度量值(或F-Score),组合精确度和召回率为一个单独的得分,
  • F-度量值定义为精确度和召回率的调和平均数(2 × Precision × Recall) / (Precision + Recall)。

3.4 混淆矩阵

对角线项目(即cells |ii|)表示正确预测的标签,非对角线项目表示错误,如下例

brown_tagged_sents = brown.tagged_sents(categories='news')
brown_sents = brown.sents(categories='news')
size = int(len(brown_tagged_sents) * 0.9)
train_sents = brown_tagged_sents[:size]
test_sents = brown_tagged_sents[size:]
t0 = nltk.DefaultTagger('NN')
t1 = nltk.UnigramTagger(train_sents, backoff=t0)
t2 = nltk.BigramTagger(train_sents, backoff=t1)

python自然语言处理 | 学习分类文本_第3张图片
这个混淆矩阵显示常见的错误,包括NN替换为了JJ(1.6%的词),NN替换为了NNS(1.5%的词)。注意点(.)表示值为0 的单元格,对角线项目——对应正确的分类——用尖括号标记。

3.5 交叉验证

交叉验证:在不同的测试集上执行多个评估,然后组合这些评估的得分。

  • 具体而言,将原始语料细分为N个子集称为折叠。对于每一个这些的折叠,我们使用除这个折叠中的数据外其他所有数据训练模型,然后在这个折叠上测试模型。即使个别的折叠可能是太小了而不能在其上给出准确的评价分数,综合评估得分是基于大量的数据,因此是相当可靠的。
  • 采用交叉验证的优势是,它可以让我们研究不同的训练集上性能变化有多大。如果我们从所有N个训练集得到非常相似的分数,然后我们可以相当有信心,得分是准确的。另一方面,如果N个训练集上分数很大不同,那么,我们应该对评估得分的准确性持怀疑态度。

4 决策树

python机器学习 | 决策树算法介绍及实现

5 朴素贝叶斯分类器

python机器学习 | 朴素贝叶斯算法介绍及实现

6 最大熵分类器

python自然语言处理 | 学习分类文本_第4张图片

6.1 最大熵模型

python自然语言处理 | 学习分类文本_第5张图片

6.2 熵的最大化

python自然语言处理 | 学习分类文本_第6张图片

6.3 生成式分类器对比条件式分类器

python自然语言处理 | 学习分类文本_第7张图片
生成式模型与条件式模型之间的差别类似与一张地形图和一张地平线的图片之间的区别。 虽然地形图可用于回答问题的更广泛,制作一张精确的地形图也明显比制作一张精确的地平线图片更加困难。

7 为语言模式建模

python自然语言处理 | 学习分类文本_第8张图片

8 小结

python自然语言处理 | 学习分类文本_第9张图片

9 练习

https://blog.csdn.net/qq_34505594/article/details/79495984
python自然语言处理 | 学习分类文本_第10张图片

你可能感兴趣的:(python,自然语言处理)