Python与NLP实战:分类器与语义分析

内容分享6小时前发布
0 0 0

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

33、结合使用for和if语句,遍历一个电影剧本中的单词列表,并逐行打印所有大写单词。

示例代码如下:


from nltk.book import text6
for word in text6:
    if word.isupper():
        print(word)

此代码假设已安装并导入nltk库,且能正常使用text6。运行代码将遍历text6中的单词,若单词全为大写则打印出来。

34、尝试以下 Python 表达式:set(sent3) < set(text1)。这里的 sent3 和 text1 可以是列表等可迭代对象。使用不同的参数对 set() 进行实验。这个表达式有什么作用?你能想到它的一个实际应用吗?

表达式

set(sent3) < set(text1)

用于判断集合

set(sent3)

是否为集合

set(text1)



真子集

实际应用如在文本分析中,判断一篇文章的词汇是否全部包含在另一篇文章的词汇中,以此评估文章之间的词汇相关性。

35、深入了解词义消歧、语义角色标注、问答系统、机器翻译或命名实体识别等语言技术中的一种。了解开发此类系统所需的标注数据类型和数量。你认为为什么需要大量的数据?

不同语言技术所需标注数据类型和数量不同:


词义消歧

:需包含多义词在不同语境下使用的文本数据


语义角色标注

:需有句子中各成分语义角色标注的语料


问答系统

:需问答对数据


机器翻译

:需平行语料


命名实体识别

:需标注实体类型的文本数据

需要大量数据的原因:

语言具有多样性和复杂性

大量数据能覆盖更多语言现象和模式

使模型学习到更全面的语言知识

提高泛化能力和准确性

减少过拟合

以应对各种实际应用场景

36、构建一个尽可能优秀的姓名性别分类器。首先将姓名语料库(共 7900 个词)划分为三个子集:500 个词作为测试集,500 个词作为开发测试集,剩下的 6900 个词作为训练集。可以使用任意三种分类器中的一种,以及你能想到的任意特征。从一个简单的姓名性别分类器开始逐步改进,使用开发测试集来检查进展。一旦对分类器满意,就在测试集上检查其最终性能。测试集上的性能与开发测试集上的性能相比如何?这是否符合你的预期?

构建流程通常包括以下步骤:


划分语料库

:按照需求将数据集划分为训练集、开发测试集和测试集。


特征构建

:从简单特征开始,逐步构建分类器。


模型调整

:利用开发测试集不断调整特征,提升模型性能。


最终测试



– 如果测试集性能

低于

开发测试集,这是符合预期的,因为开发测试集用于模型调优,可能导致模型对其产生一定程度的过拟合。

– 如果测试集性能

与开发测试集相近



更优

,则属于理想情况,但相对较少见。

37、Senseval 2语料库包含用于训练词义消歧分类器的数据。它包含四个单词的数据:hard、interest、line和serve。选择这四个单词中的一个,并加载相应的数据:

python>>> from nltk.corpus import senseval>>> instances = senseval.instances('hard.pos')>>> size = int(len(instances) * 0.1)>>> train_set, test_set = instances[size:], instances[:size]

使用这个数据集,构建一个分类器,用于预测给定实例的正确词义标签。

以下是一个使用朴素贝叶斯分类器的示例代码来实现该功能:


import nltk
from nltk.corpus import senseval
from nltk.classify import NaiveBayesClassifier
from nltk.classify.util import accuracy

# 加载数据
instances = senseval.instances('hard.pos')
size = int(len(instances) * 0.1)
train_set, test_set = instances[size:], instances[:size]

# 特征提取函数
def feature_extractor(instance):
    features = {}
    # 这里简单地将单词作为特征,可根据实际情况修改
    for word in instance.context:
        features[word] = True
    return features

# 准备训练和测试数据
train_features = [(feature_extractor(instance), instance.senses[0]) for instance in train_set]
test_features = [(feature_extractor(instance), instance.senses[0]) for instance in test_set]

# 训练分类器
classifier = NaiveBayesClassifier.train(train_features)

# 评估分类器
acc = accuracy(classifier, test_features)
print(f'分类器准确率: {acc}')

# 预测示例
new_instance = test_set[0]
predicted_sense = classifier.classify(feature_extractor(new_instance))
print(f'预测的词义标签: {predicted_sense}')

上述代码首先加载了Senseval 2语料库中关于

hard

的实例数据,并将其划分为训练集和测试集。然后定义了一个简单的特征提取函数,将实例上下文中的单词作为特征。接着使用朴素贝叶斯分类器进行训练,并评估其在测试集上的准确率。最后对一个新实例进行了词义标签的预测。

38、从姓名性别检测、文档分类、词性标注或对话行为分类中选择一个分类任务。使用相同的训练和测试数据,以及相同的特征提取器,为该任务构建三个分类器:决策树分类器、朴素贝叶斯分类器和最大熵分类器。比较这三个分类器在所选任务上的性能。你认为如果使用不同的特征提取器,结果会有怎样的不同?

可根据实际情况选择一个分类任务,按要求构建三种分类器并比较性能。

不同特征提取器可能会因提取的特征不同,影响分类器对输入特征的理解和处理,进而改变分类结果和性能。

例如,若新特征提取器提取的特征更具代表性和区分度,分类性能可能提升。

若提取的特征质量差或冗余,性能可能下降。

39、同义词“strong”和“powerful”的搭配模式不同(尝试将它们分别与“chip”和“sales”搭配)。在这种区别中,哪些特征是相关的?构建一个分类器,预测何时应该使用每个单词。

相关特征可能有语义侧重点、搭配习惯等。构建分类器可先收集包含“strong”和“powerful”的语料,提取相关特征,如前后搭配的词、所在句子的主题等,再选择合适的机器学习算法(如决策树、朴素贝叶斯分类器等)进行训练。

40、对话行为分类器为单个帖子分配标签时,不考虑帖子所在的上下文。然而,对话行为高度依赖上下文,某些对话行为序列比其他序列更有可能出现。例如,一个是非问题对话行为更有可能得到肯定回答,而不是问候语。利用这一事实构建一个连续分类器来标注对话行为。确保考虑哪些特征可能有用。

思路为:

增强特征提取器函数,使其接受一个历史参数,该参数提供到目前为止为句子预测的标签列表;

在训练时,使用带注释的标签为特征提取器提供适当的历史信息;

在标记新句子时,根据标签器本身的输出生成历史列表。


对话行为分类



可考虑的特征如前一个帖子的对话行为类型等。

41、单词特征对于文档分类非常有用,因为文档中出现的单词能有力地表明其语义内容。然而,许多单词出现的频率非常低,而且文档中一些最具信息量的单词可能从未在训练数据中出现过。一种解决方案是使用词库,它描述了不同单词之间的关系。利用WordNet词库,增强电影评论文档分类器,使其使用能够概括文档中出现的单词的特征,从而更有可能与训练数据中发现的单词相匹配。

增强分类器的步骤如下:

导入WordNet词库;

对文档中的单词进行词形还原或查找同义词;

修改特征提取函数,使用WordNet处理后的单词作为特征;

用修改后的特征提取函数生成特征集,训练和测试分类器。

42、PP 附着语料库是一个描述介词短语附着决策的语料库。语料库中的每个实例都被编码为一个 PPAttachment 对象。假设从 nltk.corpus 导入 ppattach 后,ppattach.attachments(‘training’) 结果为 [PPAttachment(sent=‘0’, verb=’join’, noun1=’board’, prep=’as’, noun2=’director’, attachment=’V’), PPAttachment(sent=‘1’, verb=’is’, noun1=’chairman’, prep=’of’, noun2=’N.V.’, attachment=’N’), …] 。若 inst = ppattach.attachments(‘training’)[1],则 (inst.noun1, inst.prep, inst.noun2) 结果为 (‘chairman’, ‘of’, ‘N.V.’) 。现在仅选择 inst.attachment 为 N 的实例,代码为 nattach = [inst for inst in ppattach.attachments(‘training’) if inst.attachment == ‘N’] 。使用这个子语料库,构建一个分类器,尝试预测用于连接给定名词对的介词。例如,给定名词对 team 和 researchers,分类器应该预测介词 of。

以下是一个使用 Python 和 NLTK 库构建分类器来预测连接给定名词对的介词的示例代码:


import nltk
from nltk.corpus import ppattach
from nltk.classify import NaiveBayesClassifier
from nltk.classify.util import accuracy

# 盎选出 inst.attachment 为 N 的实例
nattach = [inst for inst in ppattach.attachments('training') if inst.attachment == 'N']

# 定义特征提取函数
# 这里简单地将名词对作为特征
def features(inst):
    return {'noun1': inst.noun1, 'noun2': inst.noun2}

# 准备训练数据
train_data = [(features(inst), inst.prep) for inst in nattach]

# 训练分类器,这里使用朴素贝叶斯分类器
classifier = NaiveBayesClassifier.train(train_data)

# 定义测试的名词对
noun_pair = ('team', 'researchers')

# 定义测试特征
test_features = {'noun1': noun_pair[0], 'noun2': noun_pair[1]}

# 使用分类器进行预测
predicted_prep = classifier.classify(test_features)

print(f'给定名词对 {noun_pair},预测的介词是: {predicted_prep}')

上述代码中,首先从

ppattach

语料库中筛选出

inst.attachment


N

的实例,然后定义了一个简单的特征提取函数,将名词对作为特征。接着使用这些特征和对应的介词标签训练了一个朴素贝叶斯分类器。最后,使用训练好的分类器对给定的名词对进行预测,并输出预测的介词。

43、从CoNLL – 2000分块语料库的三种分块类型中选择一种。检查数据,尝试观察构成这种分块的词性标签序列中的任何模式。使用正则表达式分块器nltk.RegexpParser开发一个简单的分块器。讨论难以可靠分块的标签序列。

可按照以下步骤操作:

从CoNLL – 2000分块语料库中选择一种分块类型;

检查所选分块类型的数据,观察词性标签序列的模式;

利用

nltk.RegexpParser

开发简单分块器;

分析并讨论难以可靠分块的标签序列。

44、早期对组块(chunk)的定义是位于间隔(chinks)之间的内容。开发一个组块分析器,先将整个句子放入一个单独的组块中,然后仅通过去除间隔来完成其余工作。借助你自己的实用程序,确定哪些标签(或标签序列)最有可能构成间隔。比较这种方法与完全基于组块规则的组块分析器在性能和简易性方面的差异。

可按以下步骤解决该问题:

开发组块分析器,将整个句子初始化为一个组块,然后通过去除间隔来进一步处理。

编写实用程序,分析语料库,确定哪些标签或标签序列常作为间隔。

分别使用基于间隔去除和基于组块规则的组块分析器处理相同语料库,对比它们的性能指标(如准确率、召回率等)和实现的简易程度。

45、对之前开发的任何分块器执行以下评估任务。(注意,大多数分块语料库存在一些内部不一致性,因此任何合理的基于规则的方法都会产生错误。)a. 在一个分块语料库的100个句子上评估你的分块器,并报告精确率、召回率和F值。b. 使用chunkscore.missed()和chunkscore.incorrect()方法来识别你的分块器所犯的错误。进行讨论。c. 将你的分块器的性能与基线分块器进行比较。

需根据实际开发的分块器,结合评估分块器的示例代码(如使用

nltk.RegexpParser


evaluate

方法等)来完成这些评估任务。

46、使用基于正则表达式的分块语法 RegexpChunk 为 CoNLL 分块语料库中的一种分块类型开发一个分块器。使用分块、切分、合并或拆分的任意规则组合。

完成步骤如下:

选择 CoNLL 分块语料库中的一种分块类型,如 NP、VP 或 PP。

分析该分块类型的词性标签序列模式。

运用正则表达式规则,如分块规则(定义哪些词性标签序列构成分块)、切分规则(定义哪些词性标签序列应从分块中移除)、合并规则(将相邻分块合并)和拆分规则(将一个分块拆分为多个分块)来构建分块语法。

使用

nltk.RegexpParser

类结合构建好的分块语法创建分块器。

对语料库中的句子进行分块测试,并根据结果调整规则以提高分块器性能。

47、将n – 元语法和Brill标注方法应用于IOB组块标注。这里不是为单词分配词性(POS)标签,而是为词性标签分配IOB标签。例如,如果标签DT(限定词)经常出现在组块的开头,它将被标记为B(开始)。评估这些组块方法相对于正则表达式组块方法的性能。

可按照以下步骤操作:

实现n – 元语法和Brill标注方法用于IOB组块标注;

实现正则表达式组块方法;

使用相同的数据集对两种方法进行评估,可通过准确率、精确率、召回率和F – 度量等指标来衡量性能并进行对比。

48、可以通过查找模糊的n元语法来确定标注性能的上限,模糊的n元语法是指在训练数据中有多种可能标注方式的n元语法。应用相同的方法来确定n元语法组块器性能的上限。

可通过查找训练数据中被标注为多种可能方式的

n 元语法

,分析这些模糊

n 元语法

的情况来确定

n 元语法组块器

性能的上限。

49、从CoNLL分块语料库的三种分块类型中选择一种。编写函数完成以下针对所选类型的任务:a. 列出与该分块类型的每个实例一起出现的所有标签序列。b. 统计每个标签序列的频率,并按频率降序生成一个排名列表;每行应包含一个整数(频率)和标签序列。c. 检查高频标签序列。以此为基础开发一个更好的分块器。

可按以下思路编写函数:

a. 遍历语料库中所选分块类型的实例,提取并记录每个实例对应的标签序列。

b. 使用字典统计每个标签序列的出现频率,再根据频率对标签序列进行降序排序。

c. 分析高频标签序列的特征和规律,基于这些规律编写正则表达式或规则,结合NLTK的RegexpParser等工具开发分块器。

50、评估部分中展示的基线分块器往往会创建比实际更大的块。例如,短语 [every/DT time/NN] [she/PRP] sees/VBZ [a/DT newspaper/NN] 包含两个连续的块,而基线分块器会错误地将前两个块合并:[every/DT time/NN she/PRP]。编写一个程序,找出这些块内部标签中哪些通常出现在块的开头,然后设计一条或多条规则来拆分这些块。将这些规则与现有的基线分块器结合起来并重新评估,看看是否能得到一个改进的基线。

可按以下步骤编写程序:

从分块语料库中提取数据。

分析块内部标签,找出通常出现在块开头的标签。

设计拆分块的规则。

将规则与现有基线分块器结合。

重新评估分块器性能。

51、开发一个名词短语分块器,将词性标注文本转换为元组列表,其中每个元组由一个动词后跟一系列名词短语和介词组成,例如将句子“the little cat sat on the mat”转换为 (‘sat’, ‘on’, ‘NP’) 这样的形式。

开发这样的分块器可按以下步骤:

定义规则,明确动词、名词短语和介词的词性标签模式;

遍历词性标注文本,识别动词;

从动词后开始,按规则识别名词短语和介词;

将动词、介词和名词短语组合成元组添加到列表中。

在 Python 中使用 NLTK 库可辅助实现,示例代码因篇幅未给出。

52、一个n元语法分块器可以使用除当前词性标签和前n – 1个分块标签之外的信息。请研究其他上下文模型,例如前n – 1个词性标签,或者前分块标签与前后词性标签的某种组合,并说明研究步骤。

可按以下步骤展开研究:

数据准备:收集标注好词性和分块信息的语料库。

特征提取:提取前n – 1个词性标签、前分块标签与前后词性标签的组合等特征。

模型训练:使用提取的特征训练n元语法分块器。

评估比较:将新模型与仅使用当前词性标签和前n – 1个分块标签的模型进行评估比较。

53、考虑n元语法标注器如何利用最近的标签来做出标注选择。现在观察分块器如何重用这些序列信息。例如,这两项任务都会利用英语中名词倾向于跟在形容词后面的信息。看起来相同的信息在两个地方被维护。随着规则集规模的增长,这是否可能成为一个问题?如果是,请推测解决这个问题的方法。

推测随着规则集规模增长可能成为问题,可通过统一信息存储、抽象规则形成通用规则库等方法解决。

54、开发一种语法变体,使用特征COUNT来区分以下句子的语法正确性:(56) a. The boy sings. b. *Boy sings. (57) a. The boys sing. b. Boys sing. (58) a. The water is precious. b. Water is precious。


首先,在原语法基础上引入`COUNT`特征,`COUNT`可取值为`'count'`(可数)和`'mass'`(不可数)。然后修改语法规则和词汇规则。例如,对于可数名词单数,要求有限定词;对于可数名词复数和不可数名词,限定词可选。

以下是修改后的示例:

% start S

# ####################
# Grammar Productions
# ####################

## S expansion productions

S -> NP[NUM=?n, COUNT=?c] VP[NUM=?n]



## NP expansion productions

NP[NUM=?n, COUNT=count] -> Det[NUM=?n] N[NUM=?n, COUNT=count]

NP[NUM=?n, COUNT=count] -> PropN[NUM=?n, COUNT=count]

NP[NUM=pl, COUNT=count] -> Det[NUM=pl] N[NUM=pl, COUNT=count]

NP[NUM=pl, COUNT=count] -> N[NUM=pl, COUNT=count]

NP[COUNT=mass] -> Det N[COUNT=mass]

NP[COUNT=mass] -> N[COUNT=mass]



## VP expansion productions

VP[TENSE=?t, NUM=?n] -> IV[TENSE=?t, NUM=?n]

VP[TENSE=?t, NUM=?n] -> TV[TENSE=?t, NUM=?n] NP



# ####################
# Lexical Productions
# ###################

## Det[NUM=sg]

-> ‘this’ | ‘every’



## Det[NUM=pl]

-> ‘these’ | ‘all’



## Det

-> ‘the’ | ‘some’ | ‘several’



## PropN[NUM=sg, COUNT=count]

-> ‘Kim’ | ‘Jody’



## N[NUM=sg, COUNT=count]

-> ‘boy’



## N[NUM=pl, COUNT=count]

-> ‘boys’



## N[COUNT=mass]

-> ‘water’



## IV[TENSE=pres, NUM=sg]

-> ‘sings’ | ‘is’



## IV[TENSE=pres, NUM=pl]

-> ‘sing’



## TV[TENSE=pres, NUM=sg]

-> ‘sees’ | ‘likes’



## TV[TENSE=pres, NUM=pl]

-> ‘see’ | ‘like’



## IV[TENSE=past]

-> ‘disappeared’ | ‘walked’



## TV[TENSE=past]

-> ‘saw’ | ‘liked’

“`

© 版权声明

相关文章

暂无评论

none
暂无评论...