Время прочтения: 3 мин.

При работе с большим количеством текстовых данных часто возникает потребность в усечении текста с целью выделения основной его сути. В целом, наличие краткой аннотации или автореферата документов может значительно ускорить процесс их обработки и фильтрации. Среди основных подходов, которые позволяют автоматизированными методами решить эту задачу, выделяют два основных: извлекающий(экстрактивный) и генерирующий (абстрактивный).

Первый извлекает из исходного текста предложения или абзацы, которые образуют собой нечто вроде автореферата, в их первоначальном виде не изменяя структуры. Второй – напротив, обобщает исходный текст, создавая при этом другой, явно ранее не представленный. К плюсам первого метода можно отметить относительную простоту реализации, правда полученный текст скорее всего будет фрагментированным. Второй метод в теории предоставляет намного более связанную информацию, но при этом имеет намного более высокую сложность разработки, а также требователен к предметной области и количеству данных.

Сегодня поговорим об извлекающем (или экстрактивном) подходе. В реализации нам поможет библиотека spacy. Импортируем библиотеки и нужную нам языковую модель (это «большая» русскоязычная модель для spacy), ее размер будет около 600 Мб. Ее можно скачать следующим образом:

python -m spacy download ru_core_news_lg).
import spacy
from collections import Counter
from string import punctuation
nlp = spacy.load("ru_core_news_lg")

Определим функцию, в которой будем считать наиболее ценные предложения. В качестве входных параметров будем принимать сам текст, нуждающийся в аннотации, и количество предложений, которые мы хотим видеть на выходе.

Для начала нам нужно токенизировать текст.

   keywords = []
    tags = ['PROPN', 'ADJ', 'NOUN', 'VERB']
    doc = nlp(text.lower())
    for token in doc:
        if(token.text in nlp.Defaults.stop_words or token.text in punctuation):
            continue
        if(token.pos_ in tags):
            keywords.append(token.text)

При токенизации лучше привести все буквы в один регистр, также одновременно можно убрать стоп-слова и использовать теги для определения нужных частей речи и имен собственных. Далее необходимо нормализовать частоту слов.

word_freq = Counter(keywords)
    max_freq = Counter(keywords).most_common(1)[0][1]
    for w in word_freq:
        word_freq[w] = (word_freq[w]/max_freq)

После определения частоты вхождения слов в текст можно посчитать «важность» каждого предложения.

sent_power={}
    for sent in doc.sents:
        for word in sent:
            if word.text in word_freq.keys():
                if sent in sent_power.keys():
                    sent_power[sent]+=word_freq[word.text]
                else:
                    sent_power[sent]=word_freq[word.text]

В конце получаем наиболее «ценные» предложения следующим образом.

summary = []
    
    sorted_x = sorted(sent_power.items(), key=lambda kv: kv[1], reverse=True)
    
    counter = 0
    for i in range(len(sorted_x)):
        summary.append(str(sorted_x[i][0]).capitalize())

        counter += 1
        if(counter >= limit):
            break
            
    return ' '.join(summary)

Проверим нашу функцию на каком-нибудь тексте, например, на описании данного метода из википедии, получив 2 предложения.

На выходе имеем.

Большинство систем суммаризации используют экстрактивный подход, когда из исходных документов выбираются некоторые оригинальные предложения для создания краткого резюме. достоинства подхода: независимость от предметной области, сравнительная простота разработки. Автоматическое реферирование, аннотирование или суммаризация — создание краткой версии (реферата, аннотации) текстового документа с помощью компьютерной программы.