В современном мире объем данных в интернете постоянно растет с огромной скоростью. Возникает логичный вопрос: как ориентироваться в этом информационном потоке?
Чтобы упростить себе задачу поиска и обобщения информации IT-энтузиасты применяют технологии генеративно обученных чат-ботов. Наиболее широкое распространение получил ChatGPT. Яндекс, в свою очередь, добавил в браузер YandexGPT, который позволяет тезисно ознакомиться с содержанием страницы. Всё чаще вакансия Prompt-инженера начинает встречаться на hh и Хабр Карьере. Специалисты и чат-боты помогают конечному пользователю экономить время для поиска необходимой информации.
Но что делать, если возможности обратиться за помощью к подобным технологиям нет? Указанные выше языковые модели нельзя интегрировать в собственные проекты, сценариев их использования много, но они всё равно ограничены.
В статье мы расскажем, как (не без нейронных сетей) можно создать простой алгоритм на Python, который поможет извлекать ключевые слова из любого текста, тем самым избавляться от ненужной информации и автоматизировать процесс анализа материалов. Мы будем работать с русским текстом, а именно — с новостными постами. Поэтому в частном случае используются пакеты для обработки, поддерживающие именно русский язык. В том числе используются модели, обученные на корпусах текстов с новостной семантикой.
Декомпозиция задачи. Описываем этапы простым языком.
Как понять, что именно необходимо “выкидывать” из оригинального текста? Стоит обратиться к одному из разделов языкознания — синтаксическому анализу. Если отвечать на вопрос, что именно в тексте передает основную информацию, то можно выделить:
грамматическую основу предложения, подлежащее + сказуемое;
синтаксические единицы, словосочетания.
В первом случае подлежащим и сказуемым чаще всего выступают существительное и глагол (в некоторых частных случаях подлежащим также может выступать глагол в форме инфинитива, а сказуемым — прилагательное или существительное). Во втором же случае, помимо упомянутых выше частей речи, встречаются еще и причастия.
Возникает вопрос: не напрасно ли обделены вниманием местоимения и наречия? Чтобы понять, почему мы не рассматриваем эти части речи, нужно еще раз оценить, как именно должен работать потенциальный алгоритм. В конечном итоге мы решаем задачу извлечения основной информации из отдельно взятого предложения. В таком случае в паре подлежащего и сказуемого “он сказал” местоимение не несет никакой смысловой нагрузки. Обособленно от всего текста невозможно понять, о ком или о чем идет речь. Если же рассматривать наречия, обозначающие признак действия, предмета или другого признака, то в контексте анализа новостных блоков нам неважно, как именно субъект выполнял те или иные действия.
Таким образом, наш алгоритм можно разбить на 2 этапа:
Определение частей речи в тексте.
Построение комбинаций слов в словосочетания.
В языкознании принято считать, что подлежащее и сказуемое не являются словосочетанием. Однако в данной статье мы будем трактовать их как словосочетание для упрощения восприятия.
Морфологический анализ. Определяем части речи.
С этого момента будет меньше воды и (наконец-то!!!) больше описания технических аспектов реализации.
Хранить информацию о входном тексте, результате его сегментации, выделенных ключевых словах и словосочетаниях мы будем в коллекции элементов doc.
Для определения частей речи в тексте необходимо сначала разбить текст на отдельные слова — токены. Чтобы не “изобретать велосипед”, мы воспользуемся функционалом библиотеки razdel, которая помогает сегментировать русский текст, а именно:
sentenize() для сегментации текста на предложения;
tokenize() для токенизации слов внутри предложения.
В doc по ключу text будет храниться оригинальный текст, а в tokens — перечень со списками всех слов.
![](https://habrastorage.org/getpro/habr/upload_files/05c/7ef/974/05c7ef974a702c618d053ef15bb579f7.png)
Перед тем, как приступить к определению части речи каждого слова, необходимо добавить фильтрацию на стоп-слова (в русском языке это в основном союзы и предлоги). Такие слова встречаются почти в каждом предложении и не несут большой информативной нагрузки, не влияют на построение ключевых словосочетаний, но добавляют много шума. Составлять список таких слов вручную не придется — достаточно воспользоваться готовыми библиотеками. Му обратимся к NLTK, в которой имеется список стоп-слов для русского языка. Его можно скачать следующим образом:
![](https://habrastorage.org/getpro/habr/upload_files/ec8/cc1/a2b/ec8cc1a2b2dfdfa947e1fd5bbebf79ab.png)
После этого приступаем к созданию функции для морфологического анализа. Непосредственно определение части речи отдельного токена будет производиться с помощью MorphAnalyzer() библиотеки pymorphy2. Для того, чтобы фильтр по частям речи работал оптимальнее, перечень необходимых частей речи (Part Of Speech или POS) мы сохраним не в список, а во множество, так поиск по нему будет производиться быстрее. Учитываются следующие части речи:
NOUN, существительное;
ADJF и ADJS, полная и краткая форма прилагательного;
VERB и INFN, глагол и инфинитив;
PRTF и PRTS, полная и краткая форма причастия.
В итоге по ключу candidates будет храниться коллекция токенов, которые прошли фильтрацию на часть речи.
![](https://habrastorage.org/getpro/habr/upload_files/fac/9b9/c5c/fac9b9c5c23985b64e6963838db0c15a.png)
Синтаксический анализ. Строим ключевые словосочетания.
Для построения словосочетаний можно было бы просто пройтись скользящим окном по каждому предложению и объединить стоящие рядом слова. Однако в русском языке связанные слова могут находиться не рядом друг с другом. Чтобы автоматизировать процесс поиска связанных внутри предложения слов, мы решили провести синтаксический анализ всех предложений и определить семантические связи.
Сначала в директорию вашего проекта необходимо скачать модель navec_news_v1_1B_250K_300d_100q.tar, которая используется в библиотеке navec. С помощью неё мы сможем строить эмбеддинги русских слов. Конкретно эта модель обучена на 1 миллиарде слов, из которых был построен словарь в 250 тысяч уникальных слов. В конечном итоге каждое слово будет описываться вектором размерностью 100. Существует модель, которая обучена на двукратном объеме слов, однако для нашей задачи достаточно и упрощенной версии.
Синтаксический анализ будет проводиться за счет функционала пакета slovnet, а точнее модели slovnet_syntax_news_v1.tar, которую также необходимо предварительно скачать и поместить в директорию проекта.
![](https://habrastorage.org/getpro/habr/upload_files/91b/459/844/91b45984468c6975fe0ce79c225aea6e.png)
На примере одного предложения мы хотим продемонстрировать принципы работы синтаксической модели. В том числе, воспользуемся написанной ранее функцией segment_text():
![](https://habrastorage.org/getpro/habr/upload_files/fa5/af5/2c0/fa5af52c0d3c0bb50018785094c714eb.png)
Теперь в doc хранится словарь:
![](https://habrastorage.org/getpro/habr/upload_files/994/fee/56c/994fee56c35afd2beccecad7a457c776.png)
Объявленная модель syntax должна принимать на вход токенизированное предложение, а не оригинальный текст (!!!), поэтому передадим в неё doc[“tokens”][0]:
![](https://habrastorage.org/getpro/habr/upload_files/190/a93/f05/190a93f050d8cc688908d6ab2a1733bf.png)
Получим:
![](https://habrastorage.org/getpro/habr/upload_files/e98/aca/abd/e98acaabd5b92eb8683a44ae12ae6586.png)
Помимо очевидного ключа text в syntax_markup.tokens хранится:
id - индекс слова во входном предложении (начинается с 1);
head_id - индекс родительского слова (в смысле семантической связи);
rel - тип семантической связи.
Можно увидеть, что у сказуемого “играла” нет родительского слова, так как оно является частью грамматической основы предложения. Соответственно, для построения словосочетаний на основе семантических связей достаточно обратиться к каждому элементу syntax_markup.tokens и определить родительское слово для текущего слова.
Для удобства поиска родительских слов создадим словарь вида {id_слова_в_предложении: само_слово}:
![](https://habrastorage.org/getpro/habr/upload_files/16e/81d/c50/16e81dc50327e3bb2915a283e116da7d.png)
Также добавим проверку, чтобы строить ключевые словосочетания только из ранее отфильтрованных по частям речи слов. В итоге по ключу collocations функция будет сохранять все уникальные составленные словосочетания.
![](https://habrastorage.org/getpro/habr/upload_files/1c5/db0/fb7/1c5db0fb7b16acbda66e6831e59c40c2.png)
Заключение.
Проверим, как работают наши функции:
![](https://habrastorage.org/getpro/habr/upload_files/3e4/1d0/4eb/3e41d04ebb06141908932b82c8345d9e.png)
Получаем на выходе:
![](https://habrastorage.org/getpro/habr/upload_files/85b/ea4/7f4/85bea47f4bb1f2b357db75ec2363341a.png)
В итоге был получен относительно простой алгоритм, который способен анализировать текст на предмет построения ключевых словосочетаний. Мы хотим еще раз подчеркнуть два момента:
-
Данный алгоритм не претендует на звание SOTA-решения. Это весьма тривиальный пайплайн, который позволяет построить словосочетания длинной в 2 слова. Для улучшения вы можете:
а. добавить древовидную структуру построения словосочетаний, чтобы их длина увеличилась;
b. добавить анализ типа семантических связей, чтобы учитывать правильный порядок слов в словосочетаниях.
Несмотря на то, что использующиеся для построения эмбеддингов и синтаксического анализа модели способны работать с любым текстом, в первую очередь они ориентированы на новостные тексты. Если вы работает, к примеру, с художественной литературой, вам лучше скачать модель navec_hudlit_v1_12B_500K_300d_100q.tar.
Спасибо за внимание!