合并单词对列表中的第一个单词,具体取决于这些单词对中的第二个单词



我有一个程序(NLTK-NER),它为我提供了这个列表:

[
    ('Barak', 'PERSON'),
    ('Obama', 'PERSON'),
    ('is', 'O'),
    ('the', 'O'),
    ('president', 'O'),
    ('of', 'O'),
    ('United', 'LOCATION'),
    ('States', 'LOCATION'),
    ('of', 'LOCATION'),
    ('America', 'LOCATION')
]

如您所见,"Barak"和"Obama"是"PERSON"类型的单词,我想将它们(以及"LOCATION"类型的单词)合并在一起,如下所示:

['Barak Obama','is','the','president', 'of','United States of America']

我该如何处理这个问题?

我们在这里要做的,本质上是将一些classified_text项目组合在一起......因此,按理说itertools.groupby()可以提供帮助。首先,我们需要一个关键函数,将标签'PERSON''LOCATION'的项目视为相似,并将所有其他项目视为不同的项目。

这有点复杂,因为我们需要一种方法来区分具有相同标签(除了 'PERSON''LOCATION' 的相邻项目),例如 ('is', 'O'), ('the', 'O')等我们可以为此使用enumerate()

>>> list(enumerate(classified_text))
[..., (2, ('is', 'O')), (3, ('the', 'O')), (4, ('president', 'O')), ...]

现在我们知道我们将提供什么作为输入groupby(),我们可以编写我们的关键函数:

def person_or_location(item):
    index, (word, tag) = item
    if tag in {'PERSON', 'LOCATION'}:
        return tag
    else:
        return index

请注意,赋值中index, (word, tag)的结构与枚举列表中每个项目的结构匹配。

一旦我们有了这个,我们可以编写另一个函数来执行实际的合并:

from itertools import groupby
def merge(tagged_text):
    enumerated_text = enumerate(tagged_text)
    grouped_text = groupby(enumerated_text, person_or_location)
    return [
        ' '.join(word for index, (word, tag) in group)
        for key, group in grouped_text
    ]

这是在行动:

>>> merge(classified_text)
['Barak Obama', 'is', 'the', 'president', 'of', 'United States of America']

这是我想到的第一件事,很确定它可以优化,但这是一个好的开始。

    classified_text = [('Barak', 'PERSON'), ('Obama', 'PERSON'), ('is', 'O'), ('the', 'O'), ('president', 'O'), ('of', 'O'), ('United', 'LOCATION'), ('States', 'LOCATION'), ('of', 'LOCATION'), ('America', 'LOCATION')]
    # Reverse the list so it pops the first element
    classified_text.reverse()
    # Create an aux list to store the result and add the first item
    new_text = [classified_text.pop(), ]
    # Iterate over the text
    while classified_text:
        old_word = new_text[-1]
        new_word = classified_text.pop()
        # If previous word has same type, merge. 
        # Avoid merging 'O' types
        if old_word[1] == new_word[1] and new_word[1] != 'O':
            new_text[-1] = (
                ' '.join((old_word[0], new_word[0])),
                new_word[1],
            )
        # If not just add the tuple
        else:
            new_text.append(new_word)
    # Remove the types from the list and you have your result
    new_text = [x[0] for x in new_text]

最新更新