NLP:词中的数学( 二 )


下一步我们要探索将第2章中的词转换成连续值 , 而非只表示词出现数目的离散整数 , 也不只是表示特定词出现与否的二值位向量 。 将词表示为连续空间之后 , 就可以使用更令人激动的数学方法来对这些表示进行运算 。 我们的目标是寻找词的数值表示 , 这些表示在某种程度上刻画了词所代表的信息内容或重要度 。 我们要等到在第4章中才能看到如何将这些信息内容转换成能够表示词的意义的数值 。
本章将会考察以下3种表示能力逐步增强的对词及其在文档中的重要度进行表示的方法:

  • 词袋——词出现频率或词频向量;
  • n-gram袋——词对(2-gram)、三元组(3-gram)等的计数;
  • TF-IDF向量——更好地表示词的重要度的得分 。
重要说明
TF-IDF表示词项频率(term frequency)乘以逆文档频率(inverse document frequency) 。 在上一章中我们曾经学到过 , 词项频率是指每个词在某篇文档中的出现次数 。 而逆文档频率指的是文档集合中的文档总数除以某个词出现的文档总数 。
上述3种技术中的每一种都可以独立应用或者作为NLP流水线的一部分使用 。 由于它们都基于频率 , 因此都是统计模型 。 在本书的后面部分 , 我们会看到很多更深入观察词之间关系、模式和非线性关系的方法 。
但是 , 这些浅层的NLP机器已经很强大 , 对于很多实际应用已经很有用 , 例如垃圾邮件过滤和情感分析 。
3.1 词袋在第2章我们构建了文本的第一个向量空间模型 。 我们使用了每个词的独热向量 , 然后将所有这些向量用二进制OR运算(或者截断和 , clipped sum)组合以创建文本的向量表示 。 如果被加载到一个诸如Pandas DataFrame的数据结构中 , 这种二值的词袋向量也可以为文档检索提供一个很棒的索引 。
接下来考虑一个更有用的向量表示方法 , 它计算词在给定文本中的出现次数或者频率 。 这里引入第一个近似假设 , 假设一个词在文档中出现的次数越多 , 那么该词对文档的意义的贡献就越大 。 相比于多次提到“cats”和“gravity”的文档 , 一篇多次提到“wings”和“rudder”的文档可能会与涉及喷气式飞机或者航空旅行的主题更相关 。 或者 , 我们给出了很多表达正向情感的词 , 如good、best、joy和fantastic , 一篇文档包含的这类词越多 , 就认为它越可能包含了正向情感 。 然而可以想象 , 一个只依赖这些简单规则的算法可能会出错或者误导用户 。
下面给出了一个统计词出现次数很有用的例子:
>>> from nltk.tokenize import TreebankWordTokenizer>>> sentence = """The faster Harry got to the store, the faster Harry,...the faster, would get home.""">>> tokenizer = TreebankWordTokenizer()>>> tokens = tokenizer.tokenize(sentence.lower())>>> tokens['the', 'faster', 'harry', 'got', 'to', 'the', 'store', ',', 'the', 'faster', 'harry', ',', 'the', 'faster', ',', 'would', 'get', 'home', '.']我们希望通过简单的列表(list) , 来从文档中得到独立的词及其出现次数 。 Python的字典可以很好地实现这一目标 , 由于同时要对词计数 , 因此可以像前面章节那样使用Counter:
>>> from collections import Counter>>> bag_of_words = Counter(tokens)>>> bag_of_wordsCounter({'the': 4,'faster': 3,'harry': 2,'got': 1,'to': 1,'store': 1,',': 3,'would': 1,'get': 1,'home': 1,'.': 1})使用Python中任意一种较好的字典实现 , 键的次序都会发生变换 。 新的次序针对存储、更新和检索做了优化 , 而不是为了保持显示的一致性 , 包含在原始语句词序中的信息内容被忽略 。
注意
collections.Couter对象是一个无序的集合(collection) , 也称为袋(bag)或者多重集合(multiset) 。 基于所使用的平台和Python版本 , 我们发现Counter会以某种看似合理的次序来显示 , 就像词库序或者词条在语句中出现的先后词序一样 。 但是 , 对于标准的Pythondict , 我们不能依赖词条(键)在Counter中的次序 。


推荐阅读