Извлечение событий из новостных статей

Количество текста, генерируемого каждый день, ошеломляет. Миллионы каналов данных публикуются в виде новостных статей, блогов, сообщений, рукописей и многого другого, и возможность автоматически систематизировать их и обрабатывать их становится незаменимой.

Благодаря улучшениям в алгоритмах нейронных сетей, значительному увеличению мощности компьютера и легкому доступу к комплексным фреймворкам обработка естественного языка никогда не казалась такой привлекательной. Одно из его распространенных приложений называется «Извлечение событий», которое представляет собой процесс сбора информации о периодических инцидентах, обнаруженных в текстах, с автоматическим определением информации о том, что и когда произошло.

Например:

2018/10 - Правительство президента Дональда Трампа запретило странам импортировать иранскую нефть с изъятиями в семь стран.

2019/04 - Госсекретарь США Майк Помпео объявил, что его страна больше не будет открывать исключения после истечения крайнего срока.

2019/05 - Соединенные Штаты отказались от исключений, которые позволили странам импортировать нефть из Ирана, не подвергаясь санкциям США.

Эта способность контекстуализировать информацию позволяет нам связывать распределенные во времени события и ассимилировать их эффекты, а также то, как набор эпизодов разворачивается во времени. Это ценные идеи, которыми руководствуются такие организации, как EventRegistry и Primer.AI, которые предоставляют технологии различным секторам рынка.

В этой статье мы собираемся создать простой скрипт извлечения событий, который принимает новостные ленты и выводит события.

Получите данные

Первый шаг - собрать данные. Это может быть любой тип текстового контента, если он может быть представлен на временной шкале. Здесь я решил использовать newsapi, простой API источника новостей с бесплатным планом для разработчиков до 500 запросов в день. Ниже приведены функции, созданные для обработки запросов:

Эта последняя функция возвращает список из примерно 2000 статей по конкретному запросу. Наша цель - просто извлекать события, поэтому, чтобы упростить процесс, мы сохраняем только заголовки (теоретически заголовки должны составлять основное сообщение новостей).

Это оставляет нам фрейм данных, подобный приведенному ниже, включая даты, описания и заголовки.

Придать смысл предложениям

Когда наши заголовки готовы, нам нужно представить их машиночитаемым способом. Обратите внимание, что здесь мы пропускаем весь этап предварительной обработки, поскольку это не является целью статьи. Но если вы начинаете с НЛП, не забудьте включить эти базовые шаги предварительной обработки перед применением моделей → вот хороший учебник.

Чтобы придать значение независимым словам и, следовательно, целым предложениям, давайте воспользуемся предварительно обученной моделью встраивания слов Spacy (en_core_web_lg). В качестве альтернативы вы можете использовать любую предварительно обученную модель представления слов (Word2Vec, FastText, GloVe…).

По умолчанию Spacy считает вектор предложения средним между его векторами-маркерами. Это упрощенный подход, который не учитывает порядок слов при кодировании предложения. Для более сложной стратегии взгляните на такие модели, как Sent2Vec и SkipThoughts. Эта статья о неконтролируемом реферировании дает отличное введение в SkipThoughts.

А пока давайте будем простыми:

Итак, каждый заголовок будет иметь соответствующий 300-мерный массив, как показано ниже:

Сгруппируйте эти векторы

Несмотря на то, что мы фильтруем наши статьи по поисковому запросу, разные темы могут возникать из одного и того же запроса. Например, поиск по запросу «Париж» может привести к следующему:

Париж объединяется после разрушительного пожара

Or:

Легенда бразильского футбола Пеле попал в больницу в Париже

Чтобы сгруппировать статьи по разным темам, мы будем использовать алгоритм кластеризации.

В этом конкретном случае я хотел попробовать алгоритм DBSCAN, потому что он не требует предварительного указания количества кластеров. Вместо этого он сам определяет, сколько кластеров нужно создать, и их размеры.

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

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

В общем, поскольку мы хотим получить очень похожие предложения в одном кластере, целью должно быть значение, которое возвращает большее количество классов. По этой причине я выбрал число от 0,08 до 0,12. Ознакомьтесь с документацией Scikit Learn, чтобы узнать больше об этом и других параметрах.

Ниже приведены некоторые кластеры и их размеры:

Класс -1 обозначает предложения без кластера, а остальные - кластерные индексы. Самые большие кластеры должны отражать наиболее комментируемые темы.

Давайте посмотрим на один из кластеров:

Конвертировать в события

Следующий шаг - расположить эти предложения по времени и отфильтровать их по релевантности. Здесь я решил отображать по одной статье в день, чтобы график был четким и последовательным.

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

Для этого мы можем кластеризовать ежедневные заголовки и для каждого кластера выбирать ближайший к центру кластера. Вот функции для поиска центрального вектора по списку предложений:

Наконец, с помощью Plotly мы можем найти способ построить удобную временную диаграмму:

Вот и все. Используя 2000 случайных статей, мы создали скрипт для извлечения и организации событий. Только представьте, насколько полезным может быть применение этой техники к миллионам статей каждый день. Возьмем в качестве примера фондовые рынки и влияние ежедневных новостей, и мы можем начать изучать ценность извлечения событий.

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

Спасибо, за то что прочитали эту статью. Эта статья была посвящена НЛП и извлечению событий. Если вы хотите больше узнать о данных и машинном обучении, обязательно подпишитесь на мой профиль и не стесняйтесь оставлять любые идеи, комментарии или проблемы.