2017-01-10 11 views
2

У меня есть программа (NLTK-NER), который предоставляет мне этот список:Объединить первые слова в списке слов-пар, в зависимости от второго слова в этих парах

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

Как вы можете увидеть «Барак» и «Обама» слова типа «Person», и я хочу, чтобы объединить их (и слова типа «МЕСТОПОЛОЖЕНИЕ») вместе, как это:

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

Как я могу подойти к этой проблеме?

ответ

2

Что мы ищем, чтобы сделать здесь, по существу, является группа некоторые пункты 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'] 
+1

Вау, это намного лучше, чем я бы сделал это. –

1

Это первое, что мне пришло в голову, уверен, что его можно оптимизировать, но это хорошее начало.

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]