2. 我们如何能自动提取概括文本风格和内容的关键词和短语?
3. Python 编程语言为上述工作提供了哪些工具和技术?
4. 自然语言处理中的有哪些有趣的挑战?
1.1 语言计算:文本和单词
python入门
NLTK 入门
from nltk.book import *
import nltk
#找到这些文本
print(text1)
print(text2)
print(text3)
搜索文本
#词语索引视图显示一个指 定单词的每一次出现,连同一些上下文一起显示。
#查一下《白鲸记》中的词 monstrous:
print(text1.concordance("monstrous"))
#使用 text2.concordance("affe ction")搜索《理智与情感》中的词 affection
print(text2.concordance("affection"))
#还有哪些词出现在相似的上下文中?我们可以通过在被查询的 文本名后添加函数名 similar,然后在括号中插入相关的词来查找到。
print(text1.similar("monstrous"))
print(text2.similar("monstrous"))
#函数common_contexts允许我们研究两个或两个以上的词共同的上下文
text2.common_contexts(["monstrous", "very"])
#图. 美国总统就职演说词汇分布图:可以用来研究随时间推移语言使用上的变化
text4.dispersion_plot(["citizens", "democracy", "freedom", "duties", "America"])
计数词汇
#文本中出现的词和标点符号为单位算出文本从头到尾的长度
print(len(text3))
##set(text3) 获得 text3 的词汇表
print(list(set(text3))[:10])
#得到一个词汇项的排序表
#这个 表以各种标点符号开始,然后是以 A开头的词汇。大写单词排在小写单词前面。
print(list(sorted(set(text3)))[:10])
print(len(set(text3)))
# 对文本词汇丰富度进行测量
#每个字平均被使用 了 16 次(我们需要确保 Python 使用的是浮点除法):
print(len(text3) / len(set(text3)))
#计数一个词在文本中出现的次数,计算一个特定的词
#在文本中占据的百分比。
print(text3.count("smote"))
print(100 * text4.count("a") / len(text4))
#text5 中 lol 出现了多少次?它占文本全部词数的百分比是多少?
print(text5.count("lol"))
print(100 * text5.count("lol") / len(text5))
#定义函数
#对文本词汇丰富度进行测量
def lexical_diversity(text):
return len(text) / len(set(text))
#文本中占据的百分比
def percentage(count, total):
return 100 * count / total
print(lexical_diversity(text3))
print(percentage(text4.count("a"), len(text4)))
1.2 近观 Python:将文本当做词链表
链表
sent1 = ["Call", "me", "Ishmael", "."]
print(len(sent1))
print(lexical_diversity(sent1))
print(sent2)
print(sent3)
#连接
print(sent1 + sent4)
#追加
sent1.append("Some")
print(sent1)
索引列表
#索引
print(text4[173])
#也可以反过来做;找出一个词第一次出现的索引
print(text4.index("awaken"))
#切片
print(text5[16715:16735])
#索引从零开始:第 0 个元素写作 sent[0],其实是第 1 个词“word1”;而句子的第 9 个元素是“word10”。
#原因很简单:Python 从计算机内存中的链表获取内容的时 候,我们要告诉它向前多少个元素。因此,向前 0 个元素使它留在第一个元素上。
sent = ['word1', 'word2', 'word3', 'word4', 'word5', 'word6', 'word7', 'word8', 'word9', 'word10']
print(sent[0])
print(sent[9])
sent[0] = "First"
sent[9] = "Last"
sent[1:9] = ["Second", "Third"]
print(sent)
1.3 计算语言:简单的统计
saying = ['After', 'all', 'is', 'said', 'and', 'done', 'more', 'is', 'said', 'than', 'done']
tokens = set(saying)
print(tokens)
tokens = sorted(tokens)
print(tokens)
print(tokens[-2:])
频率分布
#我们如何能自动识别文本中最能体现文本的主题和风格的词汇?
#使用 FreqDist 寻找《白鲸记》中最常见的 50 个词
fdist1 = FreqDist(text1)
print(fdist1)
#注意:
##In Python 3 dict.keys() returns an iteratable but not indexable object
word_freq = [(word, freq) for (word, freq) in fdist1.most_common()]
print(word_freq[:5])
word = [word for (word, freq) in fdist1.most_common()]
print(word[:5])
freq = [freq for (word, freq) in fdist1.most_common()]
print(freq[:5])
print(word.index("whale"))
#《白鲸记》中 50 个最常用词的累积频率图,这些词占了所有标识符的将近一半
fdist1.plot(50, cumulative=True)
细粒度的选择词
#对于词汇表 V 中的每一个词 w,我们检查 len(w)是否大于 15;所有其他词汇将被忽略。
V = set(text1)
long_words = [w for w in V if len(w) > 15]
print(sorted(long_words)[:5])
V = set(text5)
long_words = [word for word in V if len(word) > 15]
print(sorted(long_words)[:5])
#寻找文本特征词汇的任务
#以下是聊天语料库中所有长度超过 7 个字符出现次数超过 7 次的词
#len(w) > 7 保证词长都超过七个字母,fdist5[w]> 7保证这些词出现超过 7 次。
fdist5 = FreqDist(text5)
print(sorted([w for w in set(text5) if len(w) > 7 and fdist5[w] > 7])[:5])
词语搭配和双连词( bigrams)
#文本中出现的搭配很能体现文本的风格
#一个搭配是异乎寻常的经常在一起出现的词序列。red wine 是一个搭配而 the wine 不是。
#一个搭配的特点是其中的词不能被类似的词置换。例如: maroon wine(粟色酒)听起来就 很奇怪。
#要获取搭配,我们先从提取文本词汇中的词对也就是双连词开始。使用函数 bigrams() 很容易实现。
a = bigrams(['more', 'is', 'said', 'than', 'done']) #生成器
print(list(a))
#除非我们更加注重包含不常见词的的情况,搭配基本上就是频繁的双连词。
#特别的,我们希 望找到比我们基于单个词的频率预期得到的更频繁出现的双连词。
#collocations()函数为我 们做这些
print(text4.collocations())
计数其他东西
#查看文本中词长的分布
print([len(w) for w in text1][:5])
#通过创造一长串数字的链表的 FreqDist,其中每个数字是文本中对应词的长度。
fdist = FreqDist([len(w) for w in text1])
length_freq = [(length, freq) for (length, freq) in fdist.most_common()]
print(length_freq[:5])
length = [length for (length, freq) in fdist.most_common()]
print(length[:5])
freq = [freq for (length, freq) in fdist.most_common()]
print(freq[:5])
#最频繁的词长度是 3
print(fdist.max())
#长度为 3 的词有 50,000 多个
print(fdist[3])
#频率
print(fdist.freq(3))
fdist.plot()
NLTK频率分布类中定义的函数
fdist.inc(sample) 增加样本
fdist['monstrous'] 计数给定样本出现的次数
fdist.freq('monstrous') 给定样本的频率
fdist.N() 样本总数
fdist.keys() 以频率递减顺序排序的样本链表
for sample in fdist: 以频率递减的顺序遍历样本
fdist.max() 数值最大的样本
fdist.tabulate() 绘制频率分布表
fdist.plot() 绘制频率分布图
fdist.plot(cumulative=True) 绘制累积频率分布图
fdist1 < fdist2 测试样本在fdist1 中出现的频率是否小于fdist2
1.4 回到 Python:决策与控制
条件
print(sent7)
print([w for w in sent7 if len(w) < 4])
print([w for w in sent7 if len(w) <= 4])
print([w for w in sent7 if len(w) == 4])
print([w for w in sent7 if len(w) != 4])
s.startswith(t) 测试 s 是否以 t 开头s.endswith(t) 测试 s 是否以 t 结尾
t in s 测试 s 是否包含 t
s.islower() 测试 s 中所有字符是否都是小写字母
s.isupper() 测试 s 中所有字符是否都是大写字母
s.isalpha() 测试 s 中所有字符是否都是字母
s.isalnum() 测试 s 中所有字符是否都是字母或数字
s.isdigit() 测试 s 中所有字符是否都是数字
s.istitle() 测试 s 是否首字母大写(s 中所有的词都首字母大写)
#测试 s 是否以 t 开头 s.startswith(t)
print(sorted([w for w in set(text1) if w.startswith('aba')])[:5])
#测试 s 是否以 t 结尾 s.endswith(t)
print(sorted([w for w in set(text1) if w.endswith('ableness')])[:5])
#测试 s 是否包含 tt in s
print(sorted([term for term in set(text4) if 'gnt' in term])[:5])
#测试 s 中所有字符是否都是小写字母 s.islower()
print(sorted(item for item in set(text4) if item.islower() and len(item) > 15)[:5])
#测试 s 是否首字母大写(s 中所有的词都首字母大写) s.istitle()
print(sorted([item for item in set(text4) if item.istitle() and len(item) > 13])[:5])
对每个元素进行操作
#链式推导
print([len(w) for w in text1][:5])
print([w.upper() for w in text1 if len(w) > 15][:5])
print(len(text1))
print(len(set(text1)))
#过滤掉所有非字母元素,从词汇表中消除数字和标 点符号。
print(len(set(word.lower() for word in text1 if word.isalpha())))
嵌套代码块
word = 'cat'
if len(word) < 5:
print("word length is less than 5")
word = 'cat'
if len(word) >= 5:
print("word length is more than 5")
else:
print("word length is less than 5")
#一个 if 语句叫做一个 控制结构 ,因为它控制缩进块中的代码是否运行。另一个控制结构是 for 循环
for word in ['Call', 'me', 'Ishmael', '.']:
print(word)
条件循环
sent1 = ['Call', 'me', 'Ishmael', '.']
for xyzzy in sent1:
if xyzzy.endswith('l'):
print(xyzzy)
#首先,我们创建一个包含 cie 或者 c ei 的词的链表,
#然后循环输出其中的每一项。
tricky = sorted([w for w in set(text2) if 'cie' in w or 'cei' in w])
print(tricky[:5])
for word in tricky:
print(word)
break
1.5 自动理解自然语言
词意消歧
在词意消歧中,我们要算出特定上下文中的词被赋予的是哪个意思
指代消解
一种更深刻的语言理解是解决“谁对谁做了什么”,即检测主语和动词的宾语
处理这个问题的 计算技术包括指代消解(anaphora resolution)——确定代词或名词短语指的是什么和 语义角色标注(semantic role labeling)——确定名词短语如何与动词相关联(如施事,受 事,工具等)。
自动生成语言
机器翻译
一旦我们有一百万或更多的句子对,就可以检测出相应的词和短语,并建立一个能用 来翻译新文本的模型。
人机对话系统
文本的含义
NLP的局限性
事实上,这是本书的目标之一,我们希望你能掌握这些知识和技能,构建 有效的自然语言处理系统,并为构建智能机器这一长期的理想做出贡献。
1.6 小结
词“type ”(类型)则是指词作为一 个特定序列字母的唯一形式。
我们使用 len(text)计数词的标识符,使用 len(set(text)) 计数词的类型。
我们使用[f(x) for x in text]对文本的每一项目进行操作。
为了获得没有大小写区分和忽略标点符号的词汇表,我们可以使用 set([w.lower() for w in text if w.isalpha()])。
我们使用 for 语句对文本中的每个词进行处理,例如 for w in t:或者 for word in text:.后面必须跟冒号和一块在每次循环被执行的缩进的代码。
我们使用 if 语句测试一个条件:if len(word)<5:。后面必须跟冒号和一块仅当条件为真时执行的缩进的代码。
频率分布是项目连同它们的频率计数的集合 (例如:一个文本中的词与它们出现的频率)
函数是指定了名字并且可以重用的代码块。函数通过 def 关键字定义,例如在 def mult(x, y)中 x 和 y 是函数的参数,起到实际数据值的占位符的作用。
函数是通过指定它的名字及一个或多个放在括号里的实参来调用,就像这样:mult(3,4)或者 len(text1)。