累加直方图中所有项的值,就是文件中的单词总数
def total_words(hist):
return sum(hist.values())
不同单词的数量恰好是词典中项的数目
def different_words(hist):
return len(hist)
最常用单词
使用元组;列表,其中每个元组包含单词和它的频率
具有映射关系的组合常用元组
下面的函数接受一个直方图并且返回一个单词频率的元组列表
def most_common(hist):
t = []
for key,value in hist.items():
t.append((value,key))
t.sort(reverse=True)
return t
每一个元组,频率在前,所以这个列表是按照频率排序。下面是输出最常用的十个单词的循环
t = most_common(hist)
for freq,word in t[:10]:
print(word,freq,sep='\t')
通过关键词sep,让print使用一个制表符(Tab)而不是空格键作为分隔符,所以第二行将对齐
可选形参
程序员也可以自己定义具有可选实参的函数
def print_most_common(hist,num=10):
t = most_common(hist)
for freq,word in t[:num]:
print(word,freq,sep='\t')
第一个形参是必须的,第二个是可选的,num的默认值是10
如果只提供了一个实参
print_most_common(hist)
num将使用默认值,如果提供了两个实参
print_most_common(hist,20)
num获得实参的值,也就是说,可选实参覆盖了默认值
如果一个函数同时拥有必选和可选两类实参,则所有的必选实参必须首先出现,可选实参紧随其后
字典差集
丛书中找到所有没出现在词表words.txt中的单词,可以认为是一个差集问题,也就是,我们应该从一个集合中找到所有没有出现在另一个集合中的单词
substract接受词典d1和d2,并返回一个新的词典,其包括d1中的所有没出现在d2中的键。由于并不关心每个键对应的值,我们将它们都设为None
def substract(d1,d2):
res = dict()
for key in d1:
if key not in d2:
res[key] = None
return res
我们可以使用process_file来为words.txt中的单词来构建一个直方图,然后使用substract
words = process_file('words.txt')
diff = substract(hist,words)
for word in diff.keys():
print(word,end' ')
随机单词
如果想从直方图中随机选择一个单词,最简单的算法是创建一个列表,其中根据其出现的频率,每个单词都有相应个数的拷贝,然后从该列表中选择单词
def random_word(h):
t = []
for word,freq in h.items():
t.extend([word]*q)
return random.choice(t)
表达式[word]*freq创建一个具有freq和word字符串拷贝的列表,除了它的实参要求是一个序列外,extend方法和append方法很像。
该算法能够满足要求,但是效率不够高,每次选择一个随机单词,都要重建一个很大的列表。一个改进是,创建列表一次,然后进行多次选择,但是列表仍然很大
替代方案:
1.使用keys来获得书中单词的列表
2.创建一个包含单词频率累计和的列表。此列表最后一项是书中单词数目n
3.选择一个从1到n的随机数,使用二分搜索找到该随机数应该被在累计和中插入的索引
4.使用该索引从单词列表中找到相应地单词
马尔科夫分析
一系列随机单词很少有意义,因为相邻的单词之间没有关系。
衡量相邻单词关系的方法之一是马尔科夫分析法,对于一个给定的单词序列,马尔科夫分析法将给出接下里单词的频率。
马尔科夫分析的结果是从每个前缀到所有可能的后缀的映射
给定此映射,能够通过以任意前缀开始并从可能的后缀中随机选择一个的方法,来生成一个随机文本。接下来可以将前缀的结尾和新的后缀组合成下一个前缀,并重复下去。
可以以任意前缀长度进行马尔科夫分析,前缀的长度被称为此分析的阶。
数据结构
选择表达的数据结构:
如何表示前缀
如何表示可能后缀的集合
如果表示从前缀到可能后缀集合的映射
对于前缀,我们需要能够从头部删除单词,并在结尾处加入单词。
可能会想到列表,但是前缀要作为字典的键,所以使用元组
元组可以通过加号运算符形成一个新的元组
def shift(prefix,word):
return prefix[1:] + (word,)
shift接受一个单词元组prefix和一个字符串word,并形成一个新的元组,它具有orefix中除第一个单词外的全部单词,然后在结尾处增加word
对于后缀,我们需要增加一个新的后缀,并选择一个随机后缀
从列表中选择一个随机元素很容易,在直方图中选择的难度更大。