使用NLTK和MaltParser解析多个句子

11
有许多与MaltParser和/或NLTK相关的问题:

现在,NLTK中有一个更稳定的MaltParser API版本:https://github.com/nltk/nltk/pull/944,但是在同时解析多个句子时存在问题。

一次解析一个句子似乎没问题:

_path_to_maltparser = '/home/alvas/maltparser-1.8/dist/maltparser-1.8/'
_path_to_model= '/home/alvas/engmalt.linear-1.7.mco'     
>>> mp = MaltParser(path_to_maltparser=_path_to_maltparser, model=_path_to_model)
>>> sent = 'I shot an elephant in my pajamas'.split()
>>> sent2 = 'Time flies like banana'.split()
>>> print(mp.parse_one(sent).tree())
(pajamas (shot I) an elephant in my)

但是解析句子列表并不会返回DependencyGraph对象:

_path_to_maltparser = '/home/alvas/maltparser-1.8/dist/maltparser-1.8/'
_path_to_model= '/home/alvas/engmalt.linear-1.7.mco'     
>>> mp = MaltParser(path_to_maltparser=_path_to_maltparser, model=_path_to_model)
>>> sent = 'I shot an elephant in my pajamas'.split()
>>> sent2 = 'Time flies like banana'.split()
>>> print(mp.parse_one(sent).tree())
(pajamas (shot I) an elephant in my)
>>> print(next(mp.parse_sents([sent,sent2])))
<listiterator object at 0x7f0a2e4d3d90> 
>>> print(next(next(mp.parse_sents([sent,sent2]))))
[{u'address': 0,
  u'ctag': u'TOP',
  u'deps': [2],
  u'feats': None,
  u'lemma': None,
  u'rel': u'TOP',
  u'tag': u'TOP',
  u'word': None},
 {u'address': 1,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 2,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'I'},
 {u'address': 2,
  u'ctag': u'NN',
  u'deps': [1, 11],
  u'feats': u'_',
  u'head': 0,
  u'lemma': u'_',
  u'rel': u'null',
  u'tag': u'NN',
  u'word': u'shot'},
 {u'address': 3,
  u'ctag': u'AT',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'AT',
  u'word': u'an'},
 {u'address': 4,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'elephant'},
 {u'address': 5,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'in'},
 {u'address': 6,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'my'},
 {u'address': 7,
  u'ctag': u'NNS',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NNS',
  u'word': u'pajamas'},
 {u'address': 8,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'Time'},
 {u'address': 9,
  u'ctag': u'NNS',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NNS',
  u'word': u'flies'},
 {u'address': 10,
  u'ctag': u'NN',
  u'deps': [],
  u'feats': u'_',
  u'head': 11,
  u'lemma': u'_',
  u'rel': u'nn',
  u'tag': u'NN',
  u'word': u'like'},
 {u'address': 11,
  u'ctag': u'NN',
  u'deps': [3, 4, 5, 6, 7, 8, 9, 10],
  u'feats': u'_',
  u'head': 2,
  u'lemma': u'_',
  u'rel': u'dep',
  u'tag': u'NN',
  u'word': u'banana'}]

为什么使用parse_sents()不能返回parse_one的可迭代对象?

不过,我可以选择变得懒惰并这样做:

_path_to_maltparser = '/home/alvas/maltparser-1.8/dist/maltparser-1.8/'
_path_to_model= '/home/alvas/engmalt.linear-1.7.mco'     
>>> mp = MaltParser(path_to_maltparser=_path_to_maltparser, model=_path_to_model)
>>> sent1 = 'I shot an elephant in my pajamas'.split()
>>> sent2 = 'Time flies like banana'.split()
>>> sentences = [sent1, sent2]
>>> for sent in sentences:
>>> ...    print(mp.parse_one(sent).tree())

但这不是我正在寻找的解决方案。我的问题是如何回答为什么parse_sent()不返回一个可迭代的parse_one(),以及如何在NLTK代码中修复它?
在@NikitaAstrakhantsev回答后,我尝试了一下,现在它输出了一棵解析树,但似乎混淆了两个句子并将其合并成一个进行解析。
# Initialize a MaltParser object with a pre-trained model.
mp = MaltParser(path_to_maltparser=path_to_maltparser, model=path_to_model) 
sent = 'I shot an elephant in my pajamas'.split()
sent2 = 'Time flies like banana'.split()
# Parse a single sentence.
print(mp.parse_one(sent).tree())
print(next(next(mp.parse_sents([sent,sent2]))).tree())

[out]:

(pajamas (shot I) an elephant in my)
(shot I (banana an elephant in my pajamas Time flies like))

从代码上看,它似乎在对两个句子进行解析之前做了一些奇怪的操作:https://github.com/nltk/nltk/blob/develop/nltk/parse/api.py#L45

NLTK中的解析器抽象类在解析之前将两个句子合并为一个,这是为什么呢?我是否错误地调用了parse_sents() ?如果是这样,正确的调用方式是什么?

1个回答

5

根据您代码示例中的内容,我发现您在这行代码中没有调用tree()函数

>>> print(next(next(mp.parse_sents([sent,sent2])))) 

在所有情况下,您都需要使用parse_one()调用tree()

否则,我不明白为什么会发生这种情况:MaltParser中的ParserIparse_one()方法没有被覆盖,它所做的一切就是简单地调用MaltParserparse_sents(),请参见代码

更新:您所说的行未被调用,因为MaltParser中覆盖了parse_sents()并直接调用了它。

我现在唯一猜测的是java库maltparser在包含多个句子的输入文件中无法正确工作(我指的是此处 - 运行java的位置)。也许原始的malt解析器已经改变了格式,现在不是'\n\n'。 不幸的是,我不能自己运行这段代码,因为maltparser.org已经连续第二天宕机了。我检查了输入文件的格式(句子之间用双端线分隔),所以python包装程序合并句子的可能性非常小。


谢谢!现在它输出了树,但是这是一棵错误的树,请参见更新的问题。 - alvas
发现了bug!!!我太瞎了 https://github.com/alvations/nltk/blob/patch-1/nltk/parse/malt.py#L56 yield '\n\n' 的缩进错了!!!天啊... - alvas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接