【问题标题】:NLTK ViterbiParser fails in parsing words that are not in the PCFG ruleNLTK ViterbiParser 无法解析不在 PCFG 规则中的单词
【发布时间】:2016-01-30 14:50:49
【问题描述】:
import nltk
from nltk.parse import ViterbiParser

def pcfg_chartparser(grammarfile):
    f=open(grammarfile)
    grammar=f.read()
    f.close()
    return nltk.PCFG.fromstring(grammar)

grammarp = pcfg_chartparser("wsjp.cfg")

VP = ViterbiParser(grammarp)
print VP
for w in sent:
    for tree in VP.parse(nltk.word_tokenize(w)):
        print tree

当我运行上面的代码时,它会为句子“关闭灯”产生以下输出 -

(S (VP(VB转)(PRT(RP关))(NP(DT)(NNS灯))))(p=2.53851e-14)

但是,它会为句子“请关闭灯”引发以下错误-

ValueError: Grammar does not cover some input words: u"'please'"

我正在通过为其提供概率上下文无关语法来构建 ViterbiParser。它在解析包含已经在语法规则中的单词的句子时效果很好。它无法解析解析器在语法规则中没有看到单词的句子。如何绕过这个限制?
我指的是这个assignment

【问题讨论】:

  • 有没有办法平滑你的概率?

标签: python nlp nltk context-free-grammar viterbi


【解决方案1】:

首先,尝试使用 (i) 命名空间和 (ii) 明确的变量名称,例如:

>>> from nltk import PCFG
>>> from nltk.parse import ViterbiParser
>>> import urllib.request
>>> response = urllib.request.urlopen('https://raw.githubusercontent.com/salmanahmad/6.863/master/Labs/Assignment5/Code/wsjp.cfg')
>>> wsjp = response.read().decode('utf8')
>>> grammar = PCFG.fromstring(wsjp)
>>> parser = ViterbiParser(grammar)
>>> list(parser.parse('turn off the lights'.split()))
[ProbabilisticTree('S', [ProbabilisticTree('VP', [ProbabilisticTree('VB', ['turn']) (p=0.002082678), ProbabilisticTree('PRT', [ProbabilisticTree('RP', ['off']) (p=0.1089101771)]) (p=0.10768769667270556), ProbabilisticTree('NP', [ProbabilisticTree('DT', ['the']) (p=0.7396712852), ProbabilisticTree('NNS', ['lights']) (p=4.61672e-05)]) (p=4.4236397464693323e-07)]) (p=1.0999324002161311e-13)]) (p=2.5385077255727538e-14)]

如果我们看语法:

>>> grammar.check_coverage('please turn off the lights'.split())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.4/dist-packages/nltk/grammar.py", line 631, in check_coverage
    "input words: %r." % missing)
ValueError: Grammar does not cover some of the input words: "'please'".

要解决生词问题,有多种选择

  • 使用wildcard非终端节点替换未知单词。想办法把check_coverage()中语法没有涵盖的单词替换成wildcard,然后用通配符解析句子

    • 这通常会降低解析器的准确性,除非您使用处理未知词的语法专门训练 PCFG,并且通配符是未知词的超集。
  • 返回到您在使用learn_pcfg.py 创建学习 PCFG 之前拥有的语法生成文件,并在终端生成中添加所有可能的单词

  • 将未知词添加到您的 pcfg 语法中,然后重新规范化权重,给未知词赋予非常小的权重(您也可以尝试更智能的平滑/插值技术)

由于这是一个家庭作业问题,我不会给出完整代码的答案。但是上面的提示应该足以解决问题。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
相关资源
最近更新 更多