模式识别是自然语言处理的一个核心部分.

以-ed结尾的词往往是过去时态动词(ref 5 chapter)

频繁使用will暗示这是新闻文本(ref 3 chapter)

可观察到的模式(词的结构和词频)恰好与特定方面的含义相关联,如时态,主题等.

我们如何知道从哪里开始寻找,哪一方面的形式与哪一方面的含义相关联?

本章回答如下问题:

  1. 怎样识别语言数据中明显用于分类的特征?
  2. 怎样构建用于自动执行语言处理任务的语言模型?
  3. 从这些模型中可以学到哪些关于语言的知识?

决策树,朴素贝叶斯分类器和最大熵分类

6.1 监督式分类

分类是为给定的输入选择正确的类标签

  • 多样分类中,每个实例可以分配多个标签
  • 开放性分类中,标签集是事先没有定义的
  • 序列分类中,将输入链表作为整体分类

建立在训练语料基础之上的分类,叫做监督式分类

文本分类器帮助下执行任务的代表性例子:

性别鉴定

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

在names语料库中,可以发现男性和女性的名字中,以a、e和i结尾的name很可能是女性,
而以k、o、r和s结尾的name很可能是男性.所以特征提取器可以从寻找给定名称的最后一个字母开始.

1
2
3
4
5
# 函数返回的字典-特征集,能把特征名称影射到它们的值.
def gender_features(word):
# 特征名称是区分大小写的字符串,通常提供一个简短可读的特征描述
# 特征值是简单类型的值,如布尔、数字和字符串.
return {'last_letter': word[-1]}

定义一个特征提取器,同事准备一些例子和与其对应的类标签

1
2
3
4
5
6
7
from nltk.corpus import names
import random
import nltk

names = ([(name, 'male') for name in names.words('male.txt')] +
[(name, 'female') for name in names.words('female.txt')])
random.shuffle(names)

使用特征提取器处理数据,并将结果链表分割成训练集和测试集.使用训练集进行训练(朴素贝叶斯分类器)

1
2
3
4
featuresets = [(gender_features(n), g) for (n, g) in names]
train_set, test_set = featuresets[500:], featuresets[:500]
# 贝叶斯分类器训练
classifier = nltk.NaiveBayesClassifier.train(train_set)

预测(使用一些没有出现在训练数据中的名字)

1
2
3
4
5
6
7
8
9
10
11
def predict(clsfir, nm):
lbl = clsfir.classify(gender_features(nm))
print('%s预测为%s' % (nm, lbl))
return lbl

predict(classifier, 'Neo')
predict(classifier, 'Trinity')
"""
Neo预测为male
Trinity预测为female
"""

利用大量未见过的数据系统的评估这个分类器

1
2
3
4
5
6
7
8
9
def evaluation(clsfir, tst_set):
acc = nltk.classify.accuracy(clsfir, tst_set)
print('测试集的精度为%4f' % acc)
return acc

evaluation(classifier, test_set)
"""
测试集的精度为0.768000
"""

最后检查分类器,确定哪些特征对于区分名字性别时最有效的

1
2
3
4
5
6
7
8
9
10

classifier.show_most_informative_features(5)
"""
Most Informative Features
last_letter = 'a' female : male = 34.2 : 1.0
last_letter = 'k' male : female = 33.0 : 1.0
last_letter = 'f' male : female = 17.4 : 1.0
last_letter = 'p' male : female = 11.3 : 1.0
last_letter = 'm' male : female = 11.2 : 1.0
"""

处理大型语料库时,构建包含所有实例特征的单独链表会占用大量的内存.此时
使用函数 nltk.classify.apply_featurs,返回一个像链表但不会在内存存储所有特征集的对象

1
2
3
4
from nltk.classify import apply_features

train_set = apply_features(gender_features, names[500:])
test_set = apply_features(gender_features, names[:500])

选择正确的特征

建立分类器的工作之一是找出哪些特征可能是相关的,以及如何表示他们

一般的,特征提取是在反复试验和错误的过程中建立的,那些信息与问题相关,是通过直觉来引导的.
它通常以”激进现实主义”的方法开始,包括你能想到的所有特征,然后检查哪些特征是实际有用的

下面代码展示的特征提取器采取了这种做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 特征集包含大量的指定特征,导致相对较小的名字语料库产生了过拟合
def gender_features(name):
features = dict()
features["firstletter"] = name[0].lower()
features["lastletter"] = name[-1].lower()
for letter in 'abcdefghigklmnopqrstuvwxyz':
features["count(%s)" % letter] = name.lower().count(letter)
features["has(%s)" % letter] = (letter in name.lower())
return features
"""
测试集的精度为0.758000
Most Informative Features
lastletter = 'a' female : male = 36.8 : 1.0
lastletter = 'k' male : female = 29.9 : 1.0
lastletter = 'f' male : female = 17.3 : 1.0
lastletter = 'p' male : female = 11.9 : 1.0
lastletter = 'v' male : female = 10.5 : 1.0
"""

所用的给定的学习算法的特征数目是有限的,如果提供太多的特征,那么该算法将高度依赖训练数据而对一般化的新例子不起作用(此问题称为过拟合).

本地多次运行,使用后一个特征提取器结果往往优于第一个,这里作者应该只是为了说明此种现象

选定初始特征集,一种能有效完善特征集的方法称为错误分析.首先选择开发集(包含用于创建模型的语料数据),然后将这种开发集分为训练集开发测试集

在这里插入图片描述

1
2
3
train_names = names[1500:]      # 训练集用于训练模型
devtest_names = names[500:1500] # 开发测试集用于执行错误分析
test_names = names[:500] # 测试集用于系统的最终评估

将语料分为适当的数据集,使用训练集来训练模型,在开发测试集上运行,这样可以生成分类器在预测名字性别时出现的错误列表.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
train_set = [(gender_features(n), g) for (n, g) in train_names]
devtest_set = [(gender_features(n), g) for (n, g) in devtest_names]
test_set = [(gender_features(n), g) for (n, g) in test_names]
classifier = nltk.NaiveBayesClassifier.train(train_set)
evaluation(classifier, devtest_set)
# 使用开发测试集生成分类器在预测名字性别时出现的错误列表
errors = []
for (name, tag) in devtest_names:
guess = classifier.classify(gender_features(name))
if guess != tag:
errors.append((tag, guess, name))
for (tag, guess, name) in sorted(errors):
print('correct=%-8s guess=%-8s name=%-30s' % (tag, guess, name))
'''
correct=female guess=male name=Cathryn
correct=female guess=male name=Coralyn
correct=female guess=male name=Daryn
correct=female guess=male name=Ellyn
correct=female guess=male name=Eryn
correct=female guess=male name=Jaquelyn
correct=female guess=male name=Jessalyn
correct=female guess=male name=Kristyn
correct=female guess=male name=Madalyn
correct=female guess=male name=Robbyn
correct=female guess=male name=Roselyn
correct=female guess=male name=Taryn
correct=male guess=female name=Aldrich
correct=male guess=female name=Dietrich
correct=male guess=female name=Frederich
correct=male guess=female name=Rich
'''

通过分析错误列表,可以发现某些多字母后缀也可以指示名字性别,如yn,ch
所以可以调整特征提取器使其包含两个字母的后缀的特征

1
2
3
def gender_features(word):
return {'suffix1': word[-1:],
'suffix2': word[-2:]}

错误分析的过程可以不断重复,检查由于新改进的分类器导致某些错误产生的模式.
每次错误分析应该选择一个不同的开发测试/训练分割,以确保该分类器不会反映开发测试集的特质

使用开发测试集来帮助开发模型,关于模型在新数据会表现多好的问题上,它将无法给出一个准确的结果,所以一定要保持测试集分离、未使用过,直到模型开发完毕.

文档分类

首先构造已标记类别的文档清单,例子中选择电影评论语料库,将每个评论归类为正面或负面.

1
2
3
4
5
6
7
8
from nltk.corpus import movie_reviews
import random
import nltk

documents = [(list(movie_reviews.words(fileid)), category)
for category in movie_reviews.categories()
for fileid in movie_reviews.fileids(category)]
random.shuffle(documents)

然后为文档定义特征提取器,这样分类器就会知道应注意哪些方面的数据.
对于文档主题识别,可以为每个词定义一个特性以表示该文档是否包含这个词.

特别的,为了限制分类器需要处理的特征数目,构建整个语料库中前2000个最频繁词的链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = list(all_words.keys())[:2000]

# 定义一个特征提取器,简单地检查这些词是否在一个给定的文档中
def document_features(document):
document_words = set(document)
features = {}
for word in word_features:
features['contains(%s)' % word] = (word in document_words)
return features

print(document_features(movie_reviews.words('pos/cv957_8737.txt')))
'''
{'contains(plot)': True, 'contains(:)': True, 'contains(two)': True,
'contains(teen)': False, 'contains(couples)': False, 'contains(go)': False, ...}
'''

现在,使用定义的特征提取器来训练分类器,并为新的电影评论加标签.
在测试集上计算其准确性来检查生成的分类器可靠性如何.同时,还可以查看那些
特征是分类器发现的并且是最有信息量的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 训练和测试分类器以进行文档分类
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))
classifier.show_most_informative_features()
'''
0.83
Most Informative Features
contains(unimaginative) = True neg : pos = 8.5 : 1.0
contains(sexist) = True neg : pos = 7.8 : 1.0
contains(schumacher) = True neg : pos = 7.5 : 1.0
contains(mena) = True neg : pos = 7.1 : 1.0
contains(atrocious) = True neg : pos = 7.1 : 1.0
contains(suvari) = True neg : pos = 7.1 : 1.0
contains(turkey) = True neg : pos = 6.9 : 1.0
contains(shoddy) = True neg : pos = 6.4 : 1.0
contains(singers) = True pos : neg = 6.2 : 1.0
contains(underwood) = True neg : pos = 5.8 : 1.0
'''

词性标注

第5章中建立了一个正则表达式标注器,通过查找词内部的组成,为词选择词性标记.
但是这个正则表达式标注器是手工标注的.
可以训练一个分类器来算出哪个后缀最有信息量
首先,找出最常见的后缀

1
2
3
4
5
6
7
8
9
10
11
from nltk.corpus import brown
import nltk

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 = list(suffix_fdist.keys())[:100]

然后定义一个特征提取器用来检查给定单词的后缀.

1
2
3
4
5
def pos_features(word):
features = {}
for suffix in common_suffixes:
features['endswith(%s)' % suffix] = word.lower().endswith(suffix)
return features

特征提取函数的行为就想有色玻璃一样,强调数据中的某些属性,并使其无法看到其他属性.
分类器在决定如何标记输入时,将完全依赖它们所强调的属性.
此时分类器将只基于给定词拥有的(如果有)常见后缀来作决定.

现在用特征提取器来训练新的”决策树”分类器(ref 6.4)

1
2
3
4
5
6
7
8
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)

print(nltk.classify.accuracy(classifier, test_set)) # 0.5689706613625062
print(classifier.classify(pos_features('cats'))) # NNS

决策树模型的优点是容易解释,NLTK可以将它们以伪代码的形式输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# depth=4,只显示决策树的前4层
print(classifier.pseudocode(depth=4))
'''
if endswith(the) == False:
if endswith(,) == False:
if endswith(s) == False:
if endswith(.) == False: return '.'
if endswith(.) == True: return '.'
if endswith(s) == True:
if endswith(was) == False: return 'PP$'
if endswith(was) == True: return 'BEDZ'
if endswith(,) == True: return ','
if endswith(the) == True: return 'AT'
'''

探索上下文语境

通过增加特征提取函数,可以修改词性标注器以利用各种词内部的其他特征(词长,所包含的音节数,前缀等).
但是只要特征提取器仅关注目标词,就无法添加依赖于词所出现的上下文语境的特征.

语境特征通常提供关于标记的强线索,如标注词fly时,如果知道它前面的词是a,能够确定它是名词而不是动词.

为了应用基于词的上下文这个特征,就不能只传递已标注的词,而是传递整个(未标注)句子,以及目标词的索引.

1
2
3
4
5
6
7
8
9
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"] = "<START>"
else:
features['prev-word'] = sentence[i - 1]
return features

使用依赖上下文的特征提取器来定义一个词性标记分类器,它的特征检测器检查一个词的上下文以便决定应该分配哪个词性标记(前面的词也作为特征)

1
2
3
4
5
6
7
8
9
10
11
12
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)
print(nltk.classify.accuracy(classifier, test_set))
# 0.7891596220785678

利用上下文特征能提高词性标注器的性能,但是它无法研究一般情况(形容词后很可能是名词,但是这个名词无法获得前面这个词的词性标记).
在一般情况下,简单的分类器总是将每一个输入与所有其他输入独立对待,但是很多情况中(如词性标注),关注的是如何解决分类问题

序列分类

获取相关分类任务之间的依赖关系,可以使用联合分类器模型为一些相关的输入选择适当的标签

在词性标注的例子中,可以使用不同的序列分类器模型为给定的句子中的所有词选择词性标签

连续分类贪婪序列分类 的序列分类器策略做法如下:

为第一个输入找到最有可能的类标签,然后在此基础上找到下一个输入的最佳标签.
这个过程可以不断重复,直到所有的输入都被贴上标签

以下示例代码中,首先扩展特征提取函数使其具有参数history,其中包含以及为句子预测的标记链表.
history中的每个标记对应sentence中的一个词(只包含已经归类的词的标记,即目标词左侧的词)

1
2
3
4
5
6
7
8
9
10
11
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"] = "<START>"
features["prev-tag"] = "<START>"
else:
features['prev-word'] = sentence[i - 1]
features["prev-tag"] = history[i - 1]
return features

定义特征提取器,继续建立序列分类器.在训练中,使用已标注的标记为特征提取器提供适当的历史信息,但标注新的句子时,基于标注器本身的输出来产生历史信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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))
'''
0.7980528511821975
'''

其他序列分类方法

序列分类的缺点是一旦做出决定便无法更改.例如决定将一个词标注为名词,但是后来发现应该是动词,那也没有办法修复此错误.
解决这个问题的方案:

  1. 采用转型策略

    转型联合分类的工作原理是为输入的标签创建一个初始值,然后反复提炼该值,尝试修复相关输入之间的不一致.(e.g. ref 5.6 Brill标注器)

  2. 为词性标记的所有可能的序列打分,选择总得分最高的序列.

    隐马尔可夫模型采取了这种方法

    隐马尔可夫模型类似于连续分类器,不光考虑输入也考虑已预测标记的历史,但不是简单的找出一个给定词的单个最好标记,
    而是为标记产生一个概率分布.然后将这些概率结合起来计算标记序列的概率得分,最后选择最高概率的标记序列.

    问题:可能的标签序列数量很多.给定包含30个标签的标记集,大约有600万亿(30^10)种方式来标记一个10个词的句子.
    为了避免单独考虑所有这些可能的序列,隐马尔可夫模型要求特征提取器只考虑最近的标记(或最近的n个标记,n很小)
    由于这种限制,它可以使用动态规划来有效的找出最有可能的标记序列.
    特别的,对于每个连续的词索引i,当前的及以前的每个可能的标记都将计算得分.这种基础的方法被最大熵马尔科夫模型
    线性链条件随机场模型所采用(为标记序列打分用的是不同的算法)

    6.2 监督式分类的举例

句子分割

句子分割可以看做是标点符号的分类任务:每当遇到可能会结束句子的符号时(如句号或问好),必须决定它是否终止了当前句子

第一步是获取一些已被分割成句子的数据,将它转换成一种适合提取特征的形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import nltk

sents = nltk.corpus.treebank_raw.sents()

# 单独句子标识符的合并链表
tokens = []

# 包含所有句子-边界标识符索引的集合
boundaries = set()
offset = 0
for sent in sents:
tokens.extend(sent)
offset += len(sent)
boundaries.add(offset - 1)

指定用于决定标点是否表示句子边界的数据特征

1
2
3
4
5
def punct_features(tokens, i):
return {'next-word-capitalized': tokens[i + 1][0].isupper(),
'prevword': tokens[i - 1].lower(),
'punct': tokens[i],
'prev-word-is-one-char': len(tokens[i - 1]) == 1}

基于特征提取器,选择所有标点符号创建一个加标签的特征集链表,然后标注他们是否是边界标识符

1
2
3
featuresets = [(punct_features(tokens, i), (i in boundaries))
for i in range(1, len(tokens) - 1)
if tokens[i] in '.?!']

使用特征集训练评估标点符号分类器

1
2
3
4
5
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

识别对话行为类型

表述行为的陈述句,问候,问题,回答,断言和说明都可以被认为是基于语言的行为类型。识别对话中隐含语言下的对话行为是理解谈话的重要步骤

利用NPS聊天语料库数据建立一个分类器,用来识别新的即时消息帖子的对话行为类型.

NPS聊天语料库(ref 2.1 节)包括超过 10000 个来自即时消息会话的帖子.
这些帖子都已经被贴上了 15 种对话行为类型中的某一种标签,eg:’陈述’、
‘情感’、’ynQuestion’、’Continuer’ .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import nltk

# 提取基本的消息数据
posts = nltk.corpus.nps_chat.xml_posts()[:10000]


# 定义一个简单的特征提取器,用于检测帖子包含什么词
def dialogue_act_features(post):
features = {}
for word in nltk.word_tokenize(post):
features['contains(%s)' % word.lower()] = True
return features


# 构造训练和测试数据
# post.get('class') 获取帖子的对话行为类型
featuresets = [(dialogue_act_features(post.text), post.get('class')) for post in posts]
"""
featuresets数据结构及部分结果
[
({'contains(now)': True, 'contains(im)': True, 'contains(left)': True, 'contains(with)': True, 'contains(this)': True, 'contains(gay)': True, 'contains(name)': True}, 'Statement'),
({'contains(:)': True, 'contains(p)': True}, 'Emotion'), ...
]
"""

# 分割数据并进行训练 测试
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.668

识别文字蕴涵

识别文字蕴涵(Recognizing textual entailment, RTE)是判断文本T内的一个给定片段是否继承另一个叫做’假设’的文本。迄今为止,已经有4个RTE挑战赛,在那里共享的开发和测试数据会提供给参赛队伍。

另外,文本和假设之间的关系并不一定是逻辑蕴含,而是能否得出’文本提供的合理证据证明假设是真实的’这一结论

可以把RTE当作一个分类任务,尝试为每一对预测真/假标签.在理想情况下,希望如果有蕴含,那么假设所表示的所有信息也应该再文本中表示.相反,如果假设中有而资料文本中没有,那么就没有蕴含.

示例中让词作为信息的代理,计数词重叠的程度(hyp_extra()方法).词的重要程度不同,一般命名实体(人,组织,地方等名称)可能更为重要,这促使我们使用 words 和 nes 提取不同的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import nltk


# rte默认没有下载,先进行下载
# nltk.download('rte')

# '识别文字蕴含'的特征提取器
def rte_features(rtepair):
# RTEFeatureExtractor 类建立了一个在文本和假设中都有的并已去除一些停用词后的词汇包
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


# Challenge 3,Pair 34(True).
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'))
"""
{'operation', 'Soviet', 'meeting', 'Davudi', 'Russia', 'terrorism.', 'Parviz', 'former', 'SCO', 'at', 'association', 'Organisation', 'binds', 'republics', 'fight', 'four', 'Asia', 'together', 'representing', 'that', 'China', 'fledgling', 'central', 'Iran', 'Shanghai', 'was', 'Co'}
{'member', 'SCO.', 'China'}
set()
{'China'}
{'member'}
"""

扩展到大型数据集

纯Python的分类不是很快,建议探索NLTK与外部机器学习包的接口技术,

查看 NLTK 网站推荐的 NLTK 支持机器学习包列表

6.3 评估(略)

测试集

准确度

精确度和召回率

  • 真阳性
  • 真阴性
  • 假阳性
  • 假阴性

  • 精确度(Precision)
    TP/(TP+FP)
  • 召回率(recall)
    TP/(TP+FN)
  • F-度量值(F-Measure)(或称 F-得分,F-Score)
    组合精度和召回率为一个单独的得分
    定义为精确度和召回率的调和平均数
    (2PrecisionRecall)/(Precision+Recall)

混淆矩阵

交叉验证

6.4 决策树(略)

  • 熵和信息增益

6.5 朴素贝叶斯分类器(略)

潜在概率模型

零计数和平滑

非二元特征

独立的朴素性

双重计数的原因

6.6 最大熵分类器(略)

最大熵模型

熵的最大化

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

6.7 为语言模式建模(略)

模型告诉我们什么?

6.8 深入阅读(略)

使用Weka, Mallet, TADM 和 MegaM

最后更新: 2019年05月09日 12:37

原始链接: https://ice-melt.github.io/2019/04/22/Python_NLP_06/

× 您的支持是我原创的动力
打赏二维码