5.2 段落处理
我们解释一句话时会使用丰富的上下文知识,一部分取决于前面的内容,一部分取决于我们的背景假设。DRT 提供了一个句子的含义如何集成到前面段落表示中的理论,但是在前面的讨论中明显缺少这两个部分。首先,一直没有尝试纳入任何一种推理;第二,我们只处理了个别句子。这些遗漏由模块nltk.inference.discourse
纠正。
段落是一个句子的序列 s<sub>1</sub>, … s<sub>n</sub>,段落线是读法的序列 s<sub>1</sub>-r<sub>i</sub>, … s<sub>n</sub>-r<sub>j</sub> ,每个序列对应段落中的一个句子。该模块按增量处理句子,当有歧义时保持追踪所有可能的线。为简单起见,下面的例子中忽略了范围歧义。
>>> dt = nltk.DiscourseTester(['A student dances', 'Every student is a person'])
>>> dt.readings()
s0 readings:
s0-r0: exists x.(student(x) & dance(x))
s1 readings:
s1-r0: all x.(student(x) -> person(x))
一个新句子添加到当前的段落时,设置参数consistchk=True
会通过每条线,即每个可接受的读法的序列的检查模块来检查一致性。在这种情况下,用户可以选择收回有问题的句子。
>>> dt.add_sentence('No person dances', consistchk=True)
Inconsistent discourse: d0 ['s0-r0', 's1-r0', 's2-r0']:
s0-r0: exists x.(student(x) & dance(x))
s1-r0: all x.(student(x) -> person(x))
s2-r0: -exists x.(person(x) & dance(x))
>>> dt.retract_sentence('No person dances', verbose=True)
Current sentences are
s0: A student dances
s1: Every student is a person
以类似的方式,我们使用informchk=True
检查新的句子φ是否对当前的段落有信息量。定理证明器将段落线中现有的句子当做假设,尝试证明φ;如果没有发现这样的证据,那么它是有信息量的。
>>> dt.add_sentence('A person dances', informchk=True)
Sentence 'A person dances' under reading 'exists x.(person(x) & dance(x))':
Not informative relative to thread 'd0'
也可以传递另一套假设作为背景知识,并使用这些筛选出不一致的读法;详情请参阅http://nltk.org/howto
上的段落 HOWTO。
discourse
模块可适应语义歧义,筛选出不可接受的读法。下面的例子调用 Glue 语义和 DRT。由于 Glue 语义模块被配置为使用的覆盖面广的 Malt 依存关系分析器,输入(Every dog chases a boy. He runs.)需要分词和标注。
>>> from nltk.tag import RegexpTagger
>>> tagger = RegexpTagger(
... [('^(chases|runs)$', 'VB'),
... ('^(a)$', 'ex_quant'),
... ('^(every)$', 'univ_quant'),
... ('^(dog|boy)$', 'NN'),
... ('^(He)$', 'PRP')
... ])
>>> rc = nltk.DrtGlueReadingCommand(depparser=nltk.MaltParser(tagger=tagger))
>>> dt = nltk.DiscourseTester(['Every dog chases a boy', 'He runs'], rc)
>>> dt.readings()
s0 readings:
s0-r0: ([],[(([x],[dog(x)]) -> ([z3],[boy(z3), chases(x,z3)]))])
s0-r1: ([z4],[boy(z4), (([x],[dog(x)]) -> ([],[chases(x,z4)]))])
s1 readings:
s1-r0: ([x],[PRO(x), runs(x)])
段落的第一句有两种可能的读法,取决于量词的作用域。第二句的唯一的读法通过条件<cite>PRO(x)`</cite>表示代词 He。现在让我们看看段落线的结果:
>>> dt.readings(show_thread_readings=True)
d0: ['s0-r0', 's1-r0'] : INVALID: AnaphoraResolutionException
d1: ['s0-r1', 's1-r0'] : ([z6,z10],[boy(z6), (([x],[dog(x)]) ->
([],[chases(x,z6)])), (z10 = z6), runs(z10)])
当我们检查段落线d0
和d1
时,我们看到读法s0-r0
,其中 every dog 超出了a boy
的范围,被认为是不可接受的,因为第二句的代词不能得到解释。相比之下,段落线d1
中的代词(重写为z24
) 通过 等式(z24 = z20)
绑定。
不可接受的读法可以通过传递参数filter=True
过滤掉。
>>> dt.readings(show_thread_readings=True, filter=True)
d1: ['s0-r1', 's1-r0'] : ([z12,z15],[boy(z12), (([x],[dog(x)]) ->
([],[chases(x,z12)])), (z17 = z12), runs(z15)])
虽然这一小段是极其有限的,它应该能让你对于我们在超越单个句子后产生的语义处理问题,以及部署用来解决它们的技术有所了解。