3.2 计算出现次数
当我们将语言学文本放在一起形成语料库时,在检查语料库前,我们很可能不知道一个具体语言现象的概率分布。例如,如果没有统计每个题材的评论数量,我们不可能知道在IMDb语料库中出现动作类电影评论的概率。在现实中,没有一个语料库会如此平衡。通过对数据集(这里,数据集包含动作类、喜剧类等类型的电影评论)中相关对象出现次数的计数,构成对语料库的统计。类似地,在检查语料库的语言学内容时,我们事先不可能知道语料库中不同单词的频率分布。
在把任何一种机器学习算法应用于语料库前,应该知道的最重要的一件事是语料库所包含的单词的基本统计信息。语料库本质上就像一本教科书,学习算法将用它作为样本(正样例)进行训练。如果你不知道单词的分布(或任何感兴趣的东西),那么你就不知道教科书提供了哪些可以学习的内容。语料库中词型(word type)的分布通常是不均衡的,如图3-1所示。Madnani(2012)提供了如何为语料库生成这种图表的指南。
图3-1:NLTK Gutenburg语料库中的频率分布
首先澄清一点。当我们说正在计算语料库中的“单词”时,我们需要明白其中的含义。词频指的是词例(即词型或词干的实例)的个数。所以,我们应该正确地说明下面这句话中有8个单词还是11个单词。这取决于“单词”的含义。
“The cat chased the mouse down the street in the dark.”
可以直接用NLTK对语料库进行词频计算。图3-2显示了IMDb语料库的一些例子。弄清楚数据集中哪些单词或短语最常用,有助于深入理解你正在使用的语料库。这里,我们给出可用于查找文本文件中50个最常见单词的源代码。
图3-2 :IMDb语料库中的频率分布
关于NLTK搭配函数的使用说明可参见http://nltk.googlecode.com/svn/trunk/doc/howto/collocations.html.
这里给出在语料库上进行词法统计时需要用到的两个基本概念:
语料库大小(N)
语料库中词例的个数。
词汇表大小(V)
语料库中词型的个数。
对任一个经过分词的语料库,都可以将每一个词例映射为一个词型,例如the出现的次数(词型the的词例个数)等。获得语料库词频分布后,可以计算两个指标:排序/频率分布(rank/frequency profile)和词频的频谱(frequency spectrum)。
为得到排序/频率分布,需要从词频列表中取出词型并用其排序替换它,最常见的词型排序是1,以此类推。为生成频谱,简单地计算具有某一频率的词型的个数即可。在这两个指标的计算结果中最明显的一点是,最高频率的排序总是被功能词(function word)(即the、a和and之类的词以及介词等)占据。在布朗语料库中,位列前10的单词占语料库大小的23%(Baroni 2009)。另一个发现是排序较低的单词在频率上呈现出许多联系。例如,在IMDb语料库的频率表中,罕用语(语料库中仅出现一次的单词)数量超过8000。在布朗语料库中,大约一半的单词只出现一次。均值或平均频率的背后隐藏着巨大的差异。在布朗语料库中,词型的平均频率是每个词型出现19次,但该均值之所以如此之大是因为少量极高频词导致的。
我们也注意到语料库中的大部分单词的词频都远低于均值,所以均值比中位数高得多,尽管众数(mode)通常为1。所以,均值对“集中趋势”并不是一个很有意义的指标,对更大规模的语料库来说更是如此。
注意:回忆下面几个统计学概念之间的区别:
·均值(平均数):值的和除以值的个数
·众数:总体(或数据集)中最常见的值。
·中位数:总体(或样本)的中间数,它将样本集分为比它大的一半和比它小的一半。
3.2.1 齐普夫定律(Zip's Law)
上节提到词型的不均衡分布是乔治·齐普夫(George Zipf)根据对各种数据集的观察在1949年首次提出的。他注意到,语料库中一个词的频率f(w)是这个词的排序r(w)的非线性递减函数,可以表示为下面这两个变量之间的函数关系:
C是一个常数,由语料库的具体情况决定,但现在我们可以认为它是语料库中最高频单词的频率。假设a是1,那么我们很快就可以看到频率是如何随排序递减的。注意,该规律是一个幂次定律(power law):频率是排序的负次幂(-a)的函数。所以,排在第一位的词出现的次数通常是排在第二位的词出现次数的两倍以及第三位的三倍,以此类推。
3.2.2 n元语法
本节介绍n元语法的概念。n元语法对自然语言处理(NLP)的许多应用都很重要,因为可以通过它们构造非常直观的语言模型(language model),用于语音识别与合成、机器翻译、索引、信息检索(IR)以及接下来我们将要看到的分类。
设想我们有一个词例(token)字符串W,由元素w1, w2, ? wn组成。现在考虑W上的滑动窗口。如果滑动窗口由一元子串(wi)组成,则这些一元子串的集合称为字符串的一元(unigram)表示;字符串中元素的个数与一元表示的个数相同。现在考虑所有的二元子串,有w1w2、w2w3等,直到最后的wn-1wn,这些称为二元(bigram)表示,对于一个长度为n的字符串,我们有n-1个二元表示。
根据之前提到的条件概率的定义,可以将已知前一个词例的条件下出现当前词例的概率定义为二元概率(bigram probability)。因此,已知前一个元素wi-1,元素wi的条件概率为:
将滑动窗口进一步扩大,已知前n-1个元素,可以定义n元概率为该元素的条件概率。即,
在任何语料库中最常见的二元子串很可能不是你所感兴趣的。它们涉及词对中频次最高的那些。这通常是烦人的功能词词对,例如,
of the
in the
on the
in a
如果你想得到更有意义的二元(和三元)子串集合,可以在语料库上运行词性(POS)标注器,比如通过NLTK提供的某个词性标注器。这样能够过滤一些二元子串得到更多的实义词词对,例如,形容词和名词:
Star Trek
Bull Run
Sidekick Brainiac
这是从结果中过滤无意义的n元子串的有效方式。但更好的解决方法是利用n元子串中词语之间的“自然亲和力”。这个方法涉及所谓的搭配(collocation)。搭配是语言中两个或以上单词远超偶然共现的频繁共现。在语料库中寻找搭配的一种有效方法是计算点互信息(Pointwise Mutual Information,PMI)。大体而言,PMI背后的直觉如下:对两个单词X和Y,我们想知道一个单词能告诉我们另一个单词多少信息。例如,给定X的一次出现x和Y的一次出现y,它们的联合概率与假设它们彼此独立时的期望值之间有多大差异?这可以表示为:
pmi
实际上,NLTK所提供的搭配函数也是利用该关系构造二元搭配。将该函数应用于IMDb语料库的二元子串,可看到如下的结果:
>>> bigram_measures = nltk.collocations.BigramAssocMeasures()
>>> finder1 = BigramCollocationFinder.from_words(imdbcorpus.words())
>>> finder1.nbest(bigram_measures.pmi, 10)
[('".(', 'Check'), ('10th', 'Sarajevo'), ('16100', 'Patranis'),
('1st', 'Avenue'), ('317', 'Riverside'), ('5000', 'Reward'),
('6310', 'Willoughby'), ('750hp', 'tire'), ('ALEX', 'MILLER'),
('Aasoo', 'Bane')]
>>> finder1.apply_freq_filter(10) #look only at collocations that occur 10 times or more
>>> finder1.nbest(bigram_measures.pmi, 10)
[('United', 'States'), ('Los', 'Angeles'), ('Bhagwan', 'Shri'),
('martial', 'arts'), ('Lan', 'Yu'), ('Devi', 'Maa'),
('New', 'York'), ('qv', ')),'), ('qv', '))'), ('I', ")'")]
>>> finder1.apply_freq_filter(15)
>>> finder1.nbest(bigram_measures.pmi, 10)
[('Bhagwan', 'Shri'), ('Devi', 'Maa'), ('New', 'York'),
('qv', ')),'), ('qv', '))'), ('I', ")'"), ('no', 'longer'),
('years', 'ago'), ('none', 'other'), ('each', 'other')]
然而,使用这个简单公式将涉及数据稀疏问题。即,过高估计了观测到的罕见事件的概率,而过低估计了未观测到的事件的概率。计算语言学的研究人员已经找到许多可以在一定程度上缓解该问题的方法,我们将在第7章讨论机器学习算法时再来详细讨论该问题。