import nltk
print(nltk.corpus.gutenberg.fileids()[:5])
#挑选这些文本的第一个 ——简·奥斯丁的《爱玛》——并给它一个简短的名称 emma,然后找出它包含多少个词
emma = nltk.corpus.gutenberg.words('austen-emma.txt')
print(len(emma))
#通过循环遍历前面列出的 gutenberg 文件标识符链表相应的 fileid,然后计算统计每个文本
from nltk.corpus import gutenberg
for fileid in gutenberg.fileids():
#raw() 函数给我们没有进行过任何语言学处理的文件的内容。告诉我们文本中出现的词汇个数,包括词之间的空格。
num_chars = len(gutenberg.raw(fileid))
#print(gutenberg.raw(fileid))
print(num_chars)
num_words = len(gutenberg.words(fileid))
print(gutenberg.words(fileid))
print(num_words)
#sents()函数把 文本划分成句子,其中每一个句子是一个词链表。
print(gutenberg.sents(fileid))
num_sents = len(gutenberg.sents(fileid))
num_vocab = len(set([w.lower() for w in gutenberg.words(fileid)]))
#平均词长、平均句子长度和本文中每个词出现的平均次数
print(int(num_chars/num_words), int(num_words/num_sents), int(num_words/num_vocab), fileid)
break
#虽然古腾堡项目包含成千上万的书籍,它代表既定的文学。考虑较不正式的语言也是 很重要的。
#NLTK的网络文本小集合的内容包括 Firefox交流论坛,在纽约无意听到的对话, 《加勒比海盗》的电影剧本,个人广告和葡萄酒的评论
from nltk.corpus import webtext
for fileid in webtext.fileids():
print(fileid,"内容:" + webtext.raw(fileid)[:10], '...', '\n')
#即时消息聊天会话语料库
#例如: 10-19- 20s_706posts.xml 包含 2006 年 10 月 19 日从 20 多岁聊天室收集的 706 个帖子。
from nltk.corpus import nps_chat
chatroom = nps_chat.posts('10-19-20s_706posts.xml')
print(chatroom[123])
#布朗语料库是第一个百万词级的英语电子语料库,由布朗大学于 1961 年创建。
#这个 语料库包含 500 个不同来源的文本,按照文体分类,如:新闻、社论等。
#以将语料库作为词链表或者句子链表来访问(每个句子本身也是一个词链表 )。 我们可以指定特定的类别或文件阅读
from nltk.corpus import brown
print(brown.categories()[:5])
print(brown.words(categories='news'))
print(brown.words(fileids=['cg22']))
#布朗语料库是一个研究文体之间的系统性差异 ——一种叫做文体学的语言学研究——很方便的资源。
#让我们来比较不同文体中的情态动词的用法
#第一步:产生特定文体的计数
from nltk.corpus import brown
news_text = brown.words(categories='news')
fdist = nltk.FreqDist([w.lower() for w in news_text])
modals = ['can', 'could', 'may', 'might', 'must', 'will']
for m in modals:
print(m + ':', fdist[m], end=" " )
#下面,我们来统计每一个感兴趣的文体。我们使用 NLTK 提供的带条件的频率分布函数
#fdist.tabulate() 绘制频率分布表
print()
cfd = nltk.ConditionalFreqDist(
(genre, word)
for genre in brown.categories()
for word in brown.words(categories=genre))
genres = ['news', 'religion', 'hobbies', 'science_fiction', 'romance', 'humor']
modals = ['can', 'could', 'may', 'might', 'must', 'will']
cfd.tabulate(conditions=genres, samples=modals)
#新闻文体中最常见的情态动词是 will,而言情文体中最常见的情态动词是 could
#路透社语料库包含 10,788 个新闻文档,共计 130 万字。这些文档分成 90 个主题,按照 “训练”和“测试”分为两组。
#因此,fileid 为“test/14826”的文档属于测试组。这样分割 是为了训练和测试算法
from nltk.corpus import reuters
print(reuters.fileids()[:5])#文档
print(len(reuters.fileids()))
print(reuters.categories()[:5])#主题
print(len(reuters.categories()))
#与布朗语料库不同,路透社语料库的类别是有互相重叠的,只是因为新闻报道往往涉及多个主题。
#我们可以查找由一个或多个文档涵盖的主题,也可以查找包含在一个或多个类别 中的文档。
#为方便起见,语料库方法既接受单个的 fileid 也接受 fileids 列表作为参数。
print(reuters.categories('training/9865')) #该文档涉及好几个主题
print(reuters.categories(['training/9865', 'training/9880']))
print(reuters.fileids('barley')[:5])
print(reuters.fileids(['barley', 'corn'])[:5])
#类似的,我们可以以文档或类别为单位查找我们想要的词或句子。
#这些文本中最开始的几个词是标题,按照惯例以大写字母存储。
print(reuters.words('training/9865')[:5])
print(reuters.words(['training/9865', 'training/9880']))
print(reuters.words(categories=['barley', 'corn']))
from nltk.corpus import inaugural
print(inaugural.fileids()[:5])
#每个文本的年代都出现在它的文件名中。要从文件名中获得年代,我们使用 fileid[:4]提取前四个字符。
print([fileid[:4] for fileid in inaugural.fileids()][:5])
#让我们来看看词汇 america 和 citizen 随时间推移的使用情况
cfd = nltk.ConditionalFreqDist(
(target, fileid[:4])
for fileid in inaugural.fileids()
for w in inaugural.words(fileid)
for target in ['america', 'citizen']
#使用 w.lower()将就职演说语料库中的词汇转换成小写。
# startswith()检查它们是否以“目 标”词汇 america 或 citizen 开始。
if w.lower().startswith(target))
cfd.plot()
许多文本语料库都包含语言学标注,有词性标注、命名实体、句法结构、语义角色等。
#NLTK 包含多国语言语料库。某些情况下你在使用这些语料库之前需要学习如何在 Python中处理字符编码
print(nltk.corpus.cess_esp.words())
print(nltk.corpus.floresta.words())
print(nltk.corpus.indian.words('hindi.pos'))
print(nltk.corpus.udhr.fileids()[:5])
print(nltk.corpus.udhr.words('Javanese-Latin1')[11:])
#条件频率分布来研究 “世界人权宣言”(udhr)语料库中不同语言版本中的字长差异
from nltk.corpus import udhr
languages = ['Chickasaw', 'English', 'German_Deutsch', 'Greenlandic_Inuktikut', 'Hungarian_Magyar', 'Ibibio_Efik']
cfd = nltk.ConditionalFreqDist(
(lang, len(word))
for lang in languages
for word in udhr.words(lang + '-Latin1'))
cfd.plot(cumulative=True)
raw = gutenberg.raw('burgess-busterbrown.txt')
print(raw[1:20])
words = gutenberg.words('burgess-busterbrown.txt')
print(words[1:10])
sents = gutenberg.sents('burgess-busterbrown.txt')
print(sents[1:3])
当语料文本被分为几类(文体、主题、作者等)时,我们可以计算每个类别独立的频率分布。
条件频率分布是频率分布的集合,每个频率分布有一个不 同的“条件”。这个条件通常是文本的类别
#频率分布计算观察到的事件,如文本中出现的词汇。
#条件频率分布需要给每个时间关联一个条件,所以不是处理一个词序列
text = ['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]
#我们必须处理的是一个配对序列
pairs = [('news', 'The'), ('news', 'Fulton'), ('news', 'County'), ...]
#每对的形式是:(条件,事件)。如果我们按文体处理整个布朗语料库,将有 15 个条件(每个文体一个条件)和 1,161,192 个事件(每一个词一个事件)。
# #FreqDist( ) 以一个简单的链表作为输入,ConditionalFreqDist( ) 以一个配对链表作为输入。
from nltk.corpus import brown
cfd = nltk.ConditionalFreqDist(
(genre, word)
for genre in brown.categories()
for word in brown.words(categories=genre))
#只看两个文体:新闻和言情。对于每个文体,我们遍历文体中的每个词以产生文体与词的配对。
genre_word = [(genre, word)
for genre in ['news', 'romance']
for word in brown.words(categories=genre)]
print(len(genre_word))
#链表 genre_word 的前几个配对将是('news',word)的形式,而最后几个配对将是('romance', word)的形式。
print(genre_word[:4])
print(genre_word[-4:])
#使用此配对链表创建一个 ConditionalFreqDist,并将它保存在一个变 量 cfd 中。
#像往常一样,我们可以输入变量的名称来检查它,并确认它有两个条件
cfd = nltk.ConditionalFreqDist(genre_word)
print(cfd)
print(cfd.conditions())
#访问这两个条件,它们每一个都只是一个频率分布:
print(cfd['news'])
print(cfd['romance'])
print(list(cfd['romance'])[:5])
print(cfd['romance']['could'])
#除了组合两个或两个以上的频率分布和更容易初始化之外,ConditionalFreqDist 还为 制表和绘图提供了一些有用的方法。
#条件是词 america 或 citizen ,被绘图的计数是在特定演讲中出现的词的次数。
#它利用了每个演讲的文件名——例如 1 865-Lincoln.txt——的前4个字符包含年代的事实。
#这段代码为文件 1865-Lincoln.txt 中每 个小写形式以america开头的词——如:Americans——产生一个配对('america', '1865')。
from nltk.corpus import inaugural
cfd = nltk.ConditionalFreqDist(
(target, fileid[:4])
for fileid in inaugural.fileids()
for w in inaugural.words(fileid)
for target in ['america', 'citizen']
if w.lower().startswith(target))
cfd.plot()
#图中的计数来源于词长 。它利用了每一种语言的文件名是语言名称后面跟 '-Latin1' (字符编码)的事实。
from nltk.corpus import udhr
languages = ['Chickasaw', 'English', 'German_Deutsch', 'Greenlandic_Inuktikut', 'Hungarian_Magyar', 'Ibibio_Efik']
cfd = nltk.ConditionalFreqDist(
(lang, len(word))
for lang in languages
for word in udhr.words(lang + '-Latin1'))
cfd.plot()
#为两种语言和长度少于 10 个字符的词汇绘制累计频率数据表
cfd.tabulate(conditions=['English', 'German_Deutsch'],
samples=range(10), cumlative=True)
#我们可以使用条件频率分布创建一个双连词表(词对,在 1.3 节介绍过 )。bigrams()函数 接受一个词汇链表,并建立一个连续的词对链表。
sent = ['In', 'the', 'beginning', 'God', 'created', 'the', 'heaven', 'and', 'the', 'earth', '.']
print(list(nltk.bigrams(sent))[:5])
#产生随机文本:此程序获得《创世记》文本中所有的双连词,然后构造一个条件频率分布来记录哪些词汇最有可能跟在给定词的后面 ;
#例如:living 后面最可能的词是 creature;generate_model()函数使用这些数据和种子词随机产生文本。
def generate_model(cfdist, word, num=15):
for i in range(num):
print(word, end=" ")
word = cfdist[word].max()
text = nltk.corpus.genesis.words('english-kjv.txt')
bigrams = nltk.bigrams(text)
cfd = nltk.ConditionalFreqDist(bigrams)
print(cfd['living'])
print(generate_model(cfd, 'living'))
NLTK 中的条件频率分布 :定义、访问和可视化一个计数的条件频率分布的常用方法和习惯用法#个Python函数:这个函数试图生成任何英语名词的复数形式。
def plural(word):
if word.endswith('y'):
return word[:-1] + 'ies'
elif word[-1] in 'sx' or word[-2:] in ['sh', 'ch']:
return word + 'es'
elif word.endswith('an'):
return word[:-2] + 'en'
else:
return word + 's'
print(plural('fairy'))
print(plural('woman'))
#在一个文件中的变量和函数定义的集合被称为一个Python 模块(module)。相关模块的集合称为一个包(package)。
#处理布朗语料库的NLTK代码是一个模块,处理各种不同的语料库的代码的集合是一个包。NLTK 的本身是包的集合,有时被称为一个库(library)。
#过滤文本:此程序计算文本的词汇表,然后删除所有在现有的词汇列表中出现的元素,只留下罕见或拼写错误的词。
def unusual_words(text):
text_vocab = set(w.lower() for w in text if w.isalpha())
english_vocab = set(w.lower() for w in nltk.corpus.words.words())
unusual = text_vocab.difference(english_vocab)
return sorted(unusual)
print(unusual_words(nltk.corpus.gutenberg.words('austen-sense.txt'))[:5])
print(unusual_words(nltk.corpus.nps_chat.words())[:5])
#还有一个停用词语料库,就是那些高频词汇,如:the,to,我们有时在进一步的处理之前想要将它们从文档中过滤。
#停用词通常几乎没有什么词汇内容,而它们的出现会使区分文 本变困难。
from nltk.corpus import stopwords
print(stopwords.words('english')[:5])
#让我们定义一个函数来计算文本中没有在停用词列表中的词的比例。
def content_fraction(text):
stopwords = nltk.corpus.stopwords.words('english')
content = [w for w in text if w.lower() not in stopwords]
return len(content) / len(text)
print(content_fraction(nltk.corpus.reuters.words()))
#另一个词汇列表是名字语料库,包括 8000 个按性别分类的名字。
#男性和女性的名字存储在单独的文件中。让我们找出同时出现在两个文件中的名字即性别暧昧的名字:
names = nltk.corpus.names
print(names.fileids())
male_names = names.words('male.txt')
female_names = names.words('female.txt')
print([w for w in male_names if w in female_names][:5])
#正如大家都知道的,以字母 a 结尾的名字几乎都是女性。我们可以在图中看到这一点以及一些其它的模式,该图是由下面的代码产生的
#条件频率分布:此图显示男性和女性名字的结尾字母;多数以 a,e 或 i 结尾的名字是女性;
#以 h 和 l 结尾的男性和女性同样多;以 k,o,r,s 和 t 结尾的更可能是男性。
cfd = nltk.ConditionalFreqDist(
(fileid, name[-1])
for fileid in names.fileids()
for name in names.words(fileid))
cfd.plot()
#一个稍微丰富的词典资源是一个表格(或电子表格),在每一行中含有一个词加一些性质。
#NLTK 中包括美国英语的 CMU 发音词典,它是为语音合成器使用而设计的。
entries = nltk.corpus.cmudict.entries()
print(len(entries))
for entry in entries[39943:39951]:
print(entry)
#每个条目由两部分组成,我们可以用一个复杂的 for 语句来一个一个的处理这些。
#我们没有写 for entry in entries:,而是用两个变量名 word 和 pron 替换 entry。
#现在,每次通过循环时,word 被分配条目的第一部分,pron 被分配条目的第二部分:
for word, pron in entries:
if len(pron) == 3:
ph1, ph2, ph3 = pron
if ph1 == 'P' and ph3 == 'T':
print(word, ph2)
#通过指定词典的名字后面跟一个包含在方括号 里的关键字(例如:词 fire)来查词典
prondict = nltk.corpus.cmudict.dict()
prondict['file']
#表格词典的另一个例子是比较词表。NLTK中包含了所谓的斯瓦迪士核心词列表(Swa desh wordlists),
#几种语言中约 200 个常用词的列表。语言标识符使用 ISO639 双字母码。
from nltk.corpus import swadesh
print(swadesh.fileids()[:5])
print(swadesh.words('en')[:5])
#可以通过在 entries()方法中指定一个语言链表来访问多语言中的同源词。更进一步,我们可以把它转换成一个简单的词典
fr2en = swadesh.entries(['fr', 'en'])
print(fr2en[:5])
translate = dict(fr2en)
print(translate['chien'])
print(translate['jeter'])
# Toolbox文件由一个大量条目的集合组成,其中每个条目由一个或多个字段组成。
#大多数字段都是可选的或重复的,这意味着这个词汇资源不能作为一个表格或电子表格来处 理。
#条目包括一系列的属性-值对,如('ps', 'V'),表示词性是'V'(动词),('ge', 'gag')表示英文注释是'gag'
from nltk.corpus import toolbox
print(toolbox.entries('rotokas.dic')[:1])
#如果我们用 automobile 替换掉(1a)中的词 motorcar,变成(1b),句子的意 思几乎保持不变:
# a. Benz is credited with the invention of the motorcar.
# b. Benz is credited with the invention of the automobile.
#因为句子中所有其他成分都保持不变,我们可以得出结论:motorcar 和 automobile 有相 同的含义即它们是同义词。
#在 WordNet的帮助下,我们可以探索这些词:
#motorcar 只有一个可能的含义,它被定义为 car.n.01,car 的第一个名词意义。car.n.01 被称为 synset 或“同义词集”
from nltk.corpus import wordnet as wn
print(wn.synsets('motorcar'))
print(wn.synset('car.n.01').lemma_names()) #注意原书代码有误
#同义词集中的每个词可以有多种含义,同义词集也有一些一 般的定义和例句:
print(wn.synset('car.n.01').definition())
print(wn.synset('car.n.01').examples())
#虽然定义帮助人们了解一个同义词集的本意,同义词集中的词往往对我们的程序更有用
#为了消除歧义,我们将这些词标注为 car.n.01.automobile,car.n.01.motorcar等。 这种同义词集和词的配对叫做词条。
# 得到指定同义词集的所有词条
print(wn.synset('car.n.01').lemmas())
# 查找特定的 词条
print(wn.lemma('car.n.01.automobile'))
# 得到一个词条对应的同义词集
print(wn.lemma('car.n.01.automobile').synset())
# 得到一个词条的“名字
print(wn.lemma('car.n.01.automobile').name())
#与词 automobile 和 motorcar 这些意义明确的只有一个同义词集的词不同,词 car 是含糊的,有五个同义词集:
print(wn.synsets('car'))
for synset in wn.synsets('car'):
print(synset.lemma_names())
#为方便起见,我们可以用下面的方式访问所有包含词 car 的词条。
print(wn.lemmas('car'))
#WordNet的同义词集对应于抽象的概念,它们并不总是有对应的英语词汇。
#这些概念在 层次结构中相互联系在一起。一些概念也很一般,如实体、状态、事件;这些被称为独一无 二的根同义词集。
#WordNet使在概念之间漫游变的容易。例如:一个如摩托车这样的概念,我们可以看到 它的更加具体(直接)的概念——下位词。
motorcar = wn.synset('car.n.01')
types_of_motorcar = motorcar.hyponyms()
print(types_of_motorcar[26])
print(sorted([lemma.name() for synset in types_of_motorcar for lemma in synset.lemmas()]))
#可以通过访问上位词来浏览层次结构。有些词有多条路径,因为它们可以归类在一个以上的分类中。
#car.n.01与 entity.n.01之间有两条路径,因为 wheeled_vehicle.n. 01 可以同时被归类为车辆和容器。
print(motorcar.hypernyms())
paths = motorcar.hypernym_paths()
print(len(paths))
print([synset.name() for synset in paths[0]][:5])
print([synset.name() for synset in paths[1]][:5])
#上位词和下位词被称为词汇关系,因为它们是同义集之间的关系,这个关系定位上下为 “是一个”层次。
#例如:一棵树的部分是它的树干,树冠等;这些都是 par t_meronyms()。一棵树的实质是包括心材和边材组成的,即 substance_meronyms()。 树木的集合形成了一个森林,即 member_holonyms():
print(wn.synset('tree.n.01').part_meronyms())
print(wn.synset('tree.n.01').substance_meronyms())
print(wn.synset('tree.n.01').member_holonyms())
#我们已经看到同义词集之间构成复杂的词汇关系网络。给定一个同义词集,我们可以遍 历 WordNet 网络来查找相关含义的同义词集。
#知道哪些词是语义相关的,对索引文本集合 非常有用,当搜索一个一般性的用语——
#例如:车辆——时就可以匹配包含具体用语——例 如豪华轿车——的文档。
#如果两个同义 词集共用一个非常具体的上位词——在上位词层次结构中处于较低层的上位词——它们一 定有密切的联系。
right = wn.synset('right_whale.n.01')
orca = wn.synset('orca.n.01')
minke = wn.synset('minke_whale.n.01')
tortoise = wn.synset('tortoise.n.01')
novel = wn.synset('novel.n.01')
print(right.lowest_common_hypernyms(minke))
print(right.lowest_common_hypernyms(orca))