上一节我们已经解读了Pdist类中的__init__函数,这一节重点关注一下Python类中的__call__函数。首先简单的回顾一下上一节提到的一段话:缺省的情况,对于未知的单词,其概率均为1/N,但是对于每一个实例,Pdist均提供一个函数重载这个缺省值。为了避免过长 的单词拥有过高的概率,我们从概率10/N出发,对于候选单词的每一个字母都除以10。
要实现这个功能,Peter Norvig大牛利用了Python中的__call__函数,在Pdist类中加入:
class Pdist( dict ):
"""A probability distribution estimated from counts in datafile."""
def __init__( self, data, N = None, missingfn = None ):
…
def _ _call_ _(self, key):
if key in self: return self[key]/self.N
else: return self.missingfn(key, self.N)
这个函数本身的意思比较清楚,通俗点讲,如果在语料库中找到了该单词及其计数,那么返回的概率就是 count(word)/N,否则就采用处理未登录词的函数,目前的缺省采用lambda函数: lambda k, N: 1./N,也就是返回1/N的概率值。
但是为什么要采用__call_函数呢?首先看一下Pythont中关于__call__的标准解释:
object.__call__(self[, args...])
Called when the instance is “called” as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.__call__(arg1, arg2, ...).
这个我一开始还没看明白,后来找了一段中文资料才算弄明白:
Python中有一个有趣的语法,只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。
换句话说,我们可以把这个类型的对象当作函数来使用,相当于重载了括号运算符。
重点是第二句话,“可以把这个类型的对象当作函数来使用”。如果读者还记着我们在第三节时定义了一个辅助函数Pw:
def Pw( word ):
pass
当时的主要目的是为了能顺利的reload( segment ),事实上,在《Beautiful Data》的源代码中,这个函数是不存在的,确切的说,Pw是Pdist类的一个对象:
Pw = Pdist(datafile('vocab_common'), N, avoid_long_words)
再回顾一下Python中__call__的作用:“可以把这个类型的对象当作函数来使用”,所以Pdist类中有了__call__函数的定义之后,其对象Pw就可以当作函数使用了。
我们在Python解释器中测试一下:
>>> reload( segment )
重新定义一个数据集data_pair
>>> data_pair = [("A", 1), ("B", 2), ("C", 3), ("D", 4)]
初始化Pdist类的一个对象Pw,这里N和missgfun都采用缺省值:
>>> Pw = segment.Pdist( data_pair )
>>> Pw.N
10.0
以下开始调用__call__函数,A,B,C,D均在data_pair中存在,因此其概率为1/10, 2/10, 3/10, 4/10:
>>> Pw( "A" )
0.10000000000000001
>>> Pw( "B" )
0.20000000000000001
>>> Pw( "C" )
0.29999999999999999
>>> Pw( "D" )
0.40000000000000002
而对于E和UNK,在data_pair中不存在,因此调用未登录词处理函数,这里默认的概率为1/N,也就是1/10:
>>> Pw( "E" )
0.10000000000000001
>>> Pw( "UNK" )
0.10000000000000001
未完待续:分词6
注:原创文章,转载请注明出处“我爱自然语言处理”:www.52nlp.cn
本文链接地址:https://www.52nlp.cn/beautiful-data-统计语言模型的应用三分词5
[...] Beautiful Data-统计语言模型的应用三:分词5 [...]