为了获得更大的灵活性,我们改变我们对待文法类别,如S,NP,V的方式,我们将这些原子标签分解为类似字典的结构,以便可以提取一系列的值作为特征。
9.1文法特征
先从一个简单的例子开始,使用字典存储特征和他们的值。
>>>kim = {'CAT':'NP', 'ORTH': 'Kim', 'REF': 'k'} >>>chase = {'CAT':'V', 'ORTH': 'chased', 'REL': 'chase'}
CAT:文法类别;ORTH:拼写;REF:给出指示物或者关系。在基于规则的文法上下文中,这样的特征和特征值对被称为特征结构。
根据需要,我们还可以添加特征
>>>chase['AGT'] = 'sbj' >>>chase['PAT'] = 'obj'
AGT :施事的角色,PAT:受事的角色,在这里是宾语。
例如,我们现在要处理句子:Kim chased Lee.
>>>sent = "Kim chased Lee" >>>tokens = sent.split() >>>lee = {'CAT':'NP', 'ORTH': 'Lee', 'REF': 'l'} >>>def lex2fs(word): ... for fs in [kim, lee, chase]: ... if fs['ORTH'] ==word: ... return fs >>>subj, verb, obj = lex2fs(tokens[0]), lex2fs(tokens[1]), lex2fs(tokens[2]) >>>verb['AGT'] = subj['REF'] #agent of 'chase' is Kim >>>verb['PAT'] =obj['REF'] #patient of 'chase' is Lee >>>for kin ['ORTH', 'REL', 'AGT', 'PAT']: #checkfeatstruct of'chase' ... print "%-5s =>%s"%(k, verb[k]) ORTH =>chased REL =>chase AGT =>k PAT =>l
同样的方法可以适用不同的动词,可以添加更多的特征,例如:
>>>surprise = {'CAT':'V', 'ORTH': 'surprised', 'REL': 'surprise', ... 'SRC': 'sbj', 'EXP': 'obj'}
句法协议
动词的形态属性与主语名词短语的属性一起变化,这种变化被成为协议(agreement)。
例如:
a. the dog runs b.*the dog run a. the dogs run b.*the dogs runs
我们可以使用改进文法的方式,来处理这种情况,下面是一个例子,但是需要注意,这种方法是非常麻烦的。
改进之前的文法:
(7) S -> NPVP NP -> DetN VP -> V Det -> 'this' N -> 'dog' V -> 'runs'
改进之后的文法:
(8) S -> NP_SGVP_SG S -> NP_PLVP_PL NP_SG-> Det_SGN_SG NP_PL-> Det_PLN_PL VP_SG-> V_SG VP_PL-> V_PL Det_SG-> 'this' Det_PL-> 'these' N_SG-> 'dog' N_PL-> 'dogs' V_SG-> 'runs' V_PL-> 'run'
为了避免这种爆炸式的增加,我们可以使用属性和约束。
使用属性和约束
Det[NUM=sg]-> 'this' Det[NUM=pl]-> 'these' N[NUM=sg]-> 'dog' N[NUM=pl]-> 'dogs' V[NUM=sg]-> 'runs' V[NUM=pl]-> 'run'
我们可以使用?n来改进:
S -> NP[NUM=?n]VP[NUM=?n] NP[NUM=?n]-> Det[NUM=?n]N[NUM=?n] VP[NUM=?n]-> V[NUM=?n]
但是有些词是对单复数没有挑剔的,有两种表示方法,很显然,第二种,是比第一种要简单明了的。
第一种:
Det[NUM=sg]-> 'the' | 'some' | 'several' Det[NUM=pl]-> 'the' | 'some' | 'several'
第二种:
Det[NUM=?n]-> 'the' | 'some' | 'several'
下面的代码演示了到目前为止在本章中介绍过的大多数想法:
>>>nltk.data.show_cfg('grammars/book_grammars/feat0.fcfg') %start S #################### #GrammarProductions #################### #S expansion productions S -> NP[NUM=?n]VP[NUM=?n] #NPexpansion productions NP[NUM=?n]-> N[NUM=?n] NP[NUM=?n]-> PropN[NUM=?n] NP[NUM=?n]-> Det[NUM=?n]N[NUM=?n] NP[NUM=pl]-> N[NUM=pl] #VPexpansion productions VP[TENSE=?t,NUM=?n]-> IV[TENSE=?t, NUM=?n] VP[TENSE=?t,NUM=?n]-> TV[TENSE=?t,NUM=?n]NP #################### #LexicalProductions #################### Det[NUM=sg]-> 'this' | 'every' Det[NUM=pl]-> 'these' | 'all' Det-> 'the' | 'some' | 'several' PropN[NUM=sg]->'Kim' | 'Jody' N[NUM=sg]-> 'dog' | 'girl' | 'car' | 'child' N[NUM=pl]-> 'dogs' | 'girls' | 'cars' | 'children' IV[TENSE=pres, NUM=sg]-> 'disappears' | 'walks' TV[TENSE=pres,NUM=sg]-> 'sees' | 'likes' IV[TENSE=pres, NUM=pl]-> 'disappear' | 'walk' TV[TENSE=pres,NUM=pl]-> 'see' | 'like' IV[TENSE=past] -> 'disappeared' | 'walked' TV[TENSE=past]-> 'saw' | 'liked'
下面的代码展示了,如何解析一句话:
如果文法无法分析输入,trees将为空,否则会包含一个或多个分析树。取决于舒服是否有句法歧义。
>>>tokens = 'Kim likes children'.split() >>>from nltk import load_parser � >>>cp = load_parser('grammars/book_grammars/feat0.fcfg', trace=2) � >>>trees = cp.nbest_parse(tokens) |.Kim .like.chil.| |[----] . .| PropN[NUM='sg']-> 'Kim' * |[----] . .| NP[NUM='sg']-> PropN[NUM='sg']* |[----> . .| S[]-> NP[NUM=?n]*VP[NUM=?n]{?n: 'sg'} |. [----] .| TV[NUM='sg',TENSE='pres']-> 'likes' * |. [----> .| VP[NUM=?n,TENSE=?t]-> TV[NUM=?n,TENSE=?t]*NP[] {?n: 'sg', ?t: 'pres'} |. . [----]| N[NUM='pl']-> 'children' * |. . [----]| NP[NUM='pl']-> N[NUM='pl']* |. . [---->| S[]-> NP[NUM=?n]*VP[NUM=?n]{?n: 'pl'} |. [---------]| VP[NUM='sg',TENSE='pres'] -> TV[NUM='sg',TENSE='pres']NP[]* |[==============]| S[]-> NP[NUM='sg']VP[NUM='sg']*
最后,可以检查分析树:
>>>for tree in trees: print tree (S[] (NP[NUM='sg'] (PropN[NUM='sg'] Kim)) (VP[NUM='sg', TENSE='pres'] (TV[NUM='sg', TENSE='pres']likes) (NP[NUM='pl'] (N[NUM='pl'] children))))
术语
像sg,pl这样的简单的值通常被成为原子。原子值的一种特殊情况是布尔值,仅仅指定一个属性是真还是假。
例如AUX代表助动词。
V[TENSE=pres,aux=+]->'can'
有的时候,我们可以将协议特征组合在一起,作为一个类别的不同部分,表示AGR的值。
属性值矩阵:AVM
[POS = N ] [ ] [AGR = [PER = 3 ]] [ [NUM = pl ]] [ [GND = fem ]]
当有复杂的属性时,可以重构文法:
S -> NP[AGR=?n]VP[AGR=?n] NP[AGR=?n]-> PropN[AGR=?n] VP[TENSE=?t,AGR=?n]-> Cop[TENSE=?t,AGR=?n]Adj Cop[TENSE=pres, AGR=[NUM=sg,PER=3]]-> 'is' PropN[AGR=[NUM=sg,PER=3]]-> 'Kim' Adj-> 'happy'