我如何在nltk中删除斜杠前的POS标签?

4

这是我的一个项目的一部分,我需要表示短语检测后的输出,格式如下 - (a,x,b),其中a、x、b是短语。我编写了代码,得到了以下输出:

(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP))
(CLAUSE (NP Jack/NNP) (VP stayed/VBD) (NP in/IN London/NNP))
(CLAUSE (NP Tom/NNP) (VP is/VBZ) (NP in/IN Kolkata/NNP))

我想让它像之前的表示一样,这意味着我必须删除'CLAUSE'、'NP'、'VP'、'VBD'、'NNP'等标记。

如何做到呢?

我尝试过的方法

首先将其写入文本文件中,进行标记化,然后使用list.remove('word')。但这完全没有帮助。

我的输入

(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP)) (CLAUSE (NP Jack/NNP) (VP stayed/VBD) (NP in/IN London/NNP))

输出结果应为

[Jack,loved,Peter], [Jack,stayed,in London] 输出结果仅根据括号,并且不包含标记。


2
请分享您代码中相关的部分。 - Assem
很奇怪因为nltk.word_tokenize(t);给我的是一个单词列表,没有标签:['Julia', 'loves', 'Peter']...你使用了不同的配置或者其他什么吗? - Assem
1
是的,'Julia loves Peter' - Assem
这是一个解析问题,而不是nltk的问题。 - Assem
@alexis 感谢您的评论。我进行了一些改进。 - Salah
显示剩余7条评论
4个回答

6

因为您标记了nltk,让我们使用NLTK的树解析器来处理您的树。我们将读入每个树,然后简单地打印出叶子节点。完成。

>>> text ="(CLAUSE (NP Jack/NNP) (VP stayed/VBD) (NP in/IN London/NNP))"
>>> tree = nltk.Tree.fromstring(text, read_leaf=lambda x: x.split("/")[0])
>>> print(tree.leaves())

['Jack', 'stayed', 'in', 'London']

lambda格式会分离每个单词/词性对并丢弃词性,只保留单词。

多棵树

我知道,你会问我如何处理一整个文件的这些树,有些树跨越多行。这就是NLTK的BracketParseCorpusReader的任务,但它期望终端以(POS word)的形式出现,而不是word/POS。我不会那样做,因为更容易欺骗Tree.fromstring()将所有树读取为一个单一树的分支:

allmytext = """
(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP))
(CLAUSE (NP Jack/NNP) (VP stayed/VBD) (NP in/IN London/NNP))
(CLAUSE (NP Tom/NNP) (VP is/VBZ) (NP in/IN Kolkata/NNP))
"""
wrapped = "(ROOT "+ allmytext + " )"  # Add a "root" node at the top
trees = nltk.Tree.fromstring(wrapped, read_leaf=lambda x: x.split("/")[0])
for tree in trees:
    print(tree.leaves())

正如你所看到的,唯一的区别是我们在文件内容周围添加了"(ROOT "" )",并使用for循环生成输出。循环为我们提供了顶级节点的子节点,即实际的树。


谢谢@alexis。这些东西很有帮助。 - Salah
欢迎您。当您看到解决问题的答案时,请通过单击其旁边的大复选标记“接受”它。(您也可以投票支持任何有用的答案)。 - alexis
我认为我不必这样做,因为“(CLAUSE(NP Jack / NNP)(VP loved / VBD)(NP Peter / NNP))”是一棵树。只需显示tree.leaves(),然后就完成了! - Salah
如果你有一种将输入分成单树子句的方法,那么你就不需要它。 - alexis

3
>>> import re
>>> clause = "(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP))"
>>> pattern = r'\w+:?(?=\/)'
>>> re.findall(pattern, clause)
['Jack', 'loved', 'Peter']

编辑完成

对于多个子句:

>>> import re
>>> pattern = r'\w+:?(?=\/)'
>>> clauses = """(CLAUSE (NP school/NN) (VP is/VBZ situated/VBN) (NP in/IN London/NNP)) (CLAUSE (NP The/DT color/NN of/IN the/DT sky/NN) (VP is/VBZ) (NP pink/NN))"""
>>> [re.findall(pattern, clause) for clause in clauses.split(' (CLAUSE ')]
[['school', 'is', 'situated', 'in', 'London'], ['The', 'color', 'of', 'the', 'sky', 'is', 'pink']]

如果子句由换行符分隔:

>>> import re
>>> pattern = r'\w+:?(?=\/)'
>>> clauses = """(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP))
... (CLAUSE (NP Jack/NNP) (VP stayed/VBD) (NP in/IN London/NNP))
... (CLAUSE (NP Tom/NNP) (VP is/VBZ) (NP in/IN Kolkata/NNP))"""
>>> [re.findall(pattern, clause) for clause in clauses.split('\n')]
[['Jack', 'loved', 'Peter'], ['Jack', 'stayed', 'in', 'London'], ['Tom', 'is', 'in', 'Kolkata']]

将输出连接成字符串:

>>> " ".join(['Jack', 'loved', 'Peter'])
'Jack loved Peter'

>>> clauses = [['Jack', 'loved', 'Peter'], ['Jack', 'stayed', 'in', 'London'], ['Tom', 'is', 'in', 'Kolkata']]
>>> [" ".join(cl) for cl in clauses]
['Jack loved Peter', 'Jack stayed in London', 'Tom is in Kolkata']

我的目标是识别短语,而不是单词。如果你取多于一个句子,你的代码将会产生不想要的输出。一个解决方案是保留大括号。你可以把这个作为输入并修改你的代码:(CLAUSE (NP school/NN) (VP is/VBZ situated/VBN) (NP in/IN London/NNP)) (CLAUSE (NP The/DT color/NN of/IN the/DT sky/NN) (VP is/VBZ) (NP pink/NN)) @alvas - Salah
也许我表达不够清楚。实际上,你能够理解我的做法完全基于短语。现在我想通过逗号和大括号将它们区分开来,以便我们可以在不同方面轻松使用,例如关联规则挖掘、文本处理等。现在我已经编辑了问题。我认为现在你已经很清楚我的目的了。感谢您的努力,@alvas。 - Salah

1

我正在尝试类似于这样的东西:

import re
tmp = '(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP))'

tmp = re.split(r'[()/ ]', tmp)
#Use 're.split()' to split by character that was not a letter.
>>> ['', 'CLAUSE', '', 'NP', 'Jack', 'NNP', '', '', 'VP', 'loved', 'VBD', '', '', 'NP', 'Peter', 'NNP', '', '']

result = (tmp[4], tmp[9], tmp[14])
>>> ('Jack', 'loved', 'Peter')

这是你想要的吗?

编辑:

我应该好好考虑一下 :(。

import re
tmp = '(CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP))'

tmp = re.sub(r'[()]', '', tmp)
>>> 'CLAUSE NP Jack/NNP VP loved/VBD NP Peter/NNP'
result = re.findall(r'[a-zA-Z]*/', tmp)
>>> ['Jack/', 'loved/', 'Peter/']
#Now create a generator.
gen = (i[:-1] for i in result)
tuple(gen)
>>> ('Jack', 'loved', 'Peter')

结果 = (tmp [4],tmp [9],tmp [14]),对于大量数据,您如何找到位置? - Salah
@SoubhikR 我应该仔细考虑一下:(。 - SimonShyu
(CLAUSE (NP 学校) (VP 位于) (NP 伦敦))(CLAUSE (NP 天空的颜色) (VP 是) (NP 粉红色)) - Salah
保留大括号,否则无法区分多行代码。不管怎样,干得好,伙计。 - Salah
谢谢您的评论,我很感激。它让我回到了正确的轨道上。:) - SimonShyu
你应该得到那个 @SimonShyu。但仍然有必要修复它。你尝试过多行吗?你可以尝试这个句子:"(CLAUSE(NP学校/NN)(VP is/VBZ situated/VBN)(NP in/IN London/NNP))(CLAUSE(NP天空/NN的颜色/NN)(VP is/VBZ)(NP粉红色/NN))"。 - Salah

0

当输出如下所示时: (CLAUSE (NP Jack/NNP) (VP loved/VBD) (NP Peter/NNP)) (CLAUSE (NP Jack/NNP) (VP stayed/VBD) (NP in/IN London/NNP)) (CLAUSE (NP Tom/NNP) (VP is/VBZ) (NP in/IN Kolkata/NNP)) 很明显它们是树形结构。因此只需使用Tree.leaves()。 以下是完整代码:

def leaves(self):
    """
    Return the leaves of the tree.

        >>> t = Tree.fromstring("(S (NP (D the) (N dog)) (VP (V chased) (NP (D the) (N cat))))")
        >>> t.leaves()
        ['the', 'dog', 'chased', 'the', 'cat']

    :return: a list containing this tree's leaves.
        The order reflects the order of the
        leaves in the tree's hierarchical structure.
    :rtype: list
    """
    leaves = []
    for child in self:
        if isinstance(child, Tree):
            leaves.extend(child.leaves())
        else:
            leaves.append(child)
    return leaves

你可以从这里找到它:http://www.nltk.org/_modules/nltk/tree.html


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