R - 通过网格解析Python NLTK树

时间:2018-01-31 00:39:29

标签: python r parsing nltk reticulate

我正在尝试使用Reticulate包从R中使用Python的NLTK包。在大多数情况下,我都取得了成功。

现在,我想使用NLTK的ne_chunk()函数执行命名实体识别(即确定哪些令牌代表命名实体以及它们代表什么类型的命名实体)。我的问题是该函数返回类nltk.tree.Tree的对象,我无法弄清楚如何在R中解析。

如果ne_chunk()最多有10个令牌标签对,它将返回一个结果,可以使用as.character()将其转换为字符,可以通过正则表达式函数进行解析(这只是黑客,我不满意)。但是,超过十对,它将返回树的简写表示,从中无法使用R方法提取有意义的数据。

这是一个最低限度可重复的例子:

library(reticulate)
nltk <- import("nltk")

sent_tokenize <- function(text, language = "english") {
  nltk$tokenize$sent_tokenize(text, language)
}
word_tokenize <- function(text, language = "english", preserve_line = FALSE) {
  nltk$tokenize$word_tokenize(text, language, preserve_line)
}
pos_tag <- function(tokens, tagset = NULL, language = "eng") {
  nltk$pos_tag(tokens, tagset, language)
}
ne_chunk <- function(tagged_tokens, binary = FALSE) {
  nltk$ne_chunk(tagged_tokens, binary)
}

text <- "Christopher is having a difficult time parsing NLTK Trees in R."
tokens <- word_tokenize(text)
tagged_tokens <- pos_tag(tokens)
ne_tagged_tokens <- ne_chunk(tagged_tokens)

以下是处理上一个示例中的文本时返回的简写:

> ne_tagged_tokens
List (11 items)

以下是ne_tagged_tokens所属的类:

> class(ne_tagged_tokens)
[1] "nltk.tree.Tree"        "python.builtin.list"   "python.builtin.object"

我对使用替代的,预先存在的R包的建议不感兴趣。

1 个答案:

答案 0 :(得分:2)

我想问题在于reticulate无法读取自定义Python对象,这很常见,所以你必须在R和Python接口之间传递Python对象和本机Python类型。

有一种方法可以使用ne_chunksTree.pformat()的输出格式更改为字符串(bracketed parse format):

>>> from nltk import word_tokenize, pos_tag, ne_chunk
>>> sent = "Christopher is having a difficult time parsing NLTK Trees in R."
>>> ne_chunk(pos_tag(word_tokenize(sent)))
Tree('S', [Tree('GPE', [('Christopher', 'NNP')]), ('is', 'VBZ'), ('having', 'VBG'), ('a', 'DT'), ('difficult', 'JJ'), ('time', 'NN'), ('parsing', 'VBG'), Tree('ORGANIZATION', [('NLTK', 'NNP'), ('Trees', 'NNP')]), ('in', 'IN'), Tree('GPE', [('R', 'NNP')]), ('.', '.')])
>>> ne_chunk(pos_tag(word_tokenize(sent))).pformat()
'(S\n  (GPE Christopher/NNP)\n  is/VBZ\n  having/VBG\n  a/DT\n  difficult/JJ\n  time/NN\n  parsing/VBG\n  (ORGANIZATION NLTK/NNP Trees/NNP)\n  in/IN\n  (GPE R/NNP)\n  ./.)'

要重新阅读,请使用Tree.fromstring()

>>> tree_str = ne_chunk(pos_tag(word_tokenize(sent))).pformat()
>>> from nltk import Tree
>>> Tree.fromstring(tree_str)
Tree('S', [Tree('GPE', ['Christopher/NNP']), 'is/VBZ', 'having/VBG', 'a/DT', 'difficult/JJ', 'time/NN', 'parsing/VBG', Tree('ORGANIZATION', ['NLTK/NNP', 'Trees/NNP']), 'in/IN', Tree('GPE', ['R/NNP']), './.'])

所以我猜想在R中这样做可能会起作用:

text <- "Christopher is having a difficult time parsing NLTK Trees in R."
ne_tagged_tokens <- ne_chunk(pos_tag(word_tokenize(tagged_tokens)))$pformat()
print(ne_tagged_tokens)

但是将字符串读回R对象应该是不可能的,因为它无法处理非本机Python Tree对象,因此some_func <- function(...{nltk$some_func(...)})不能使用{{1}因为它不是一个功能。

如果你想将Tree Tree对象的输出操作到命名实体列表中,那么你必须在Python中做这样的事情:NLTK Named Entity recognition to a Python list

然后,如果你在Python中需要这么多函数而你真的不想重新编码或使用其他R库,为什么你不用Python编写而不是坚持R.