3.4 计数其他东西

计数词汇是有用的,我们也可以计数其他东西。例如,我们可以查看文本中词长的分布,通过创造一长串数字的列表的FreqDist,其中每个数字是文本中对应词的长度:

  1. >>> [len(w) for w in text1] ![[1]](/projects/nlp-py-2e-zh/Images/4b5cae275c53c53ccc8f2f779acada3e.jpg)
  2. [1, 4, 4, 2, 6, 8, 4, 1, 9, 1, 1, 8, 2, 1, 4, 11, 5, 2, 1, 7, 6, 1, 3, 4, 5, 2, ...]
  3. >>> fdist = FreqDist(len(w) for w in text1) ![[2]](/projects/nlp-py-2e-zh/Images/3a93e0258a010fdda935b4ee067411a5.jpg)
  4. >>> print(fdist) ![[3]](/projects/nlp-py-2e-zh/Images/334be383b5db7ffe3599cc03bc74bf9e.jpg)
  5. <FreqDist with 19 samples and 260819 outcomes>
  6. >>> fdist
  7. FreqDist({3: 50223, 1: 47933, 4: 42345, 2: 38513, 5: 26597, 6: 17111, 7: 14399,
  8. 8: 9966, 9: 6428, 10: 3528, ...})
  9. >>>

我们以导出text1 中每个词的长度的列表开始[1],然后FreqDist 计数列表中每个数字出现的次数[2]。结果[3] 是一个包含 25 万左右个元素的分布,每一个元素是一个数字,对应文本中一个词标识符。但是只有 20 个不同的元素,从 1 到 20,因为只有 20 个不同的词长。也就是说,有由 1 个字符,2 个字符,…,20 个字符组成的词,而没有由 21 个或更多字符组成的词。有人可能会问不同长度的词的频率是多少?(例如,文本中有多少长度为 4 的词?长度为 5 的词是否比长度为 4 的词多?等等)。下面我们回答这个问题:

  1. >>> fdist.most_common()
  2. [(3, 50223), (1, 47933), (4, 42345), (2, 38513), (5, 26597), (6, 17111), (7, 14399),
  3. (8, 9966), (9, 6428), (10, 3528), (11, 1873), (12, 1053), (13, 567), (14, 177),
  4. (15, 70), (16, 22), (17, 12), (18, 1), (20, 1)]
  5. >>> fdist.max()
  6. 3
  7. >>> fdist[3]
  8. 50223
  9. >>> fdist.freq(3)
  10. 0.19255882431878046
  11. >>>

由此我们看到,最频繁的词长度是 3,长度为 3 的词有 50,000 多个(约占书中全部词汇的 20%)。虽然我们不会在这里追究它,关于词长的进一步分析可能帮助我们了解作者、文体或语言之间的差异。

3.1 总结了 NLTK 频率分布类中定义的函数。

表 3.1:

NLTK 频率分布类中定义的函数

  1. >>> sent7
  2. ['Pierre', 'Vinken', ',', '61', 'years', 'old', ',', 'will', 'join', 'the',
  3. 'board', 'as', 'a', 'nonexecutive', 'director', 'Nov.', '29', '.']
  4. >>> [w for w in sent7 if len(w) < 4]
  5. [',', '61', 'old', ',', 'the', 'as', 'a', '29', '.']
  6. >>> [w for w in sent7 if len(w) <= 4]
  7. [',', '61', 'old', ',', 'will', 'join', 'the', 'as', 'a', 'Nov.', '29', '.']
  8. >>> [w for w in sent7 if len(w) == 4]
  9. ['will', 'join', 'Nov.']
  10. >>> [w for w in sent7 if len(w) != 4]
  11. ['Pierre', 'Vinken', ',', '61', 'years', 'old', ',', 'the', 'board',
  12. 'as', 'a', 'nonexecutive', 'director', '29', '.']
  13. >>>

所有这些例子都有一个共同的模式:[w for w in text if condition ],其中 condition 是 Python 中的一个“测试”,得到真或者假。在前面的代码例子所示的情况中,条件始终是数值比较。然而,我们也可以使用表4.2 中列出的函数测试词汇的各种属性。

表 4.2:

一些词比较运算符

  1. >>> sorted(w for w in set(text1) if w.endswith('ableness'))
  2. ['comfortableness', 'honourableness', 'immutableness', 'indispensableness', ...]
  3. >>> sorted(term for term in set(text4) if 'gnt' in term)
  4. ['Sovereignty', 'sovereignties', 'sovereignty']
  5. >>> sorted(item for item in set(text6) if item.istitle())
  6. ['A', 'Aaaaaaaaah', 'Aaaaaaaah', 'Aaaaaah', 'Aaaah', 'Aaaaugh', 'Aaagh', ...]
  7. >>> sorted(item for item in set(sent7) if item.isdigit())
  8. ['29', '61']
  9. >>>

我们还可以创建更复杂的条件。如果 c 是一个条件,那么not c 也是一个条件。如果我们有两个条件 c<sub>1</sub> 和 c<sub>2</sub>,那么我们可以使用合取和析取将它们合并形成一个新的条件:c<sub>1</sub> and c<sub>2</sub>, c<sub>1</sub> or c<sub>2</sub>。

注意

轮到你来: 运行下面的例子,尝试解释每一条指令中所发生的事情。然后,试着自己组合一些条件。

  1. >>> sorted(w for w in set(text7) if '-' in w and 'index' in w)
  2. >>> sorted(wd for wd in set(text3) if wd.istitle() and len(wd) > 10)
  3. >>> sorted(w for w in set(sent7) if not w.islower())
  4. >>> sorted(t for t in set(text2) if 'cie' in t or 'cei' in t)