Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
В Тинькофф—журнале вышла статья «Что и зачем пишут в интернете противники вакцинации», в которой мы рассказали о результатах исследования почти трёх миллионов постов и комментариев из ВКонтакте на тему вакцинации. Самая сложная часть работы — определить, как авторы сообщений относятся к прививкам. В этой статье мы хотим рассказать о том, как мы это делали.
У трёх миллионов постов почти невозможно вручную определить отношение их авторов к вакцинации. На то, чтобы разметить выборку из 10 тысяч текстов, у нас ушло примерно 50 часов. Такими темпами весь корпус мы бы размечали 15 тысяч часов! Можно было бы отдать разметку на аутсорс, но мы пошли по более дешёвому и быстрому пути — использовали машинное обучение.
Классификация — это один из методов машинного обучения, и одна из стандартных задач обработки естественного языка: она применяется для того, чтобы распознать, например, негативные или позитивные отзывы, популярные темы в соцсетях или спам в почте.
Хотя это и часто используемый инструмент в анализе текстов, было неясно, насколько хорошо модель сможет выявить именно мнение человека по поводу вакцины. Даже при ручной разметке определить пост в ту или иную категорию было не так просто. Пока мы вручную классифицировали десять тысяч постов и комментариев, выяснилось, что чёткого разделения на противников и сторонников вакцинации не существует.
Полярность мнений по поводу вакцин оказалась велика: существует целая шкала, где на одной стороне находятся те, кто крайне негативно относится к идее «колоть себе эту гадость» , а на другой — те, кто считает, что «вакцинация – один из самых эффективных методов борьбы с эпидемиями, который есть у нашей цивилизации». Между двумя полюсами расположено множество групп: те, кто не против вакцинации, но против посягательства на личную свободу со стороны государства; те, кто согласен привиться, но зарубежной вакциной; те, кто привился, но не хочет вступать в полемику на столь чувствительную тему.
Однако сообщений, в которых вакцину прямо-таки хвалили, в интернете оказалось немного. Так немного, что мы начали относить к про-вакцинной группе посты тех, кто ничего не написал о самой вакцине, но из контекста было ясно, что человек привился. Мы отнесли к этой группе даже тех, кто упоминает, что вакцины нет в их районной поликлинике или медучреждении — это указывает на то, что человек хотел привиться. Тем не менее, анализа различий в аргументах сторонников и противников вакцинации у нас бы просто не получилось — постов, где ярко выражено позитивное мнение относительно вакцинации, было очень мало. Кроме того, сообщения сторонников вакцин плохо поддавались автоматической классификации.
По итогам ручной разметки обучающей выборки мы получили следующее соотношение записей:
Тогда мы решили более подробно рассмотреть, чем тексты противников вакцинации отличаются от всех остальных. Осталось научить этому разделению модель.
Очистка данных
При ручной разметке мы заметили, что в данных содержится существенная доля нерелевантных постов: сообщения о вакцинации животных от различных заболеваний, информация от турагентств. От таких постов нашу выборку точно следовало очистить.
Здесь и далее мы будем приводить фрагменты кода на языке Python, который использовали для анализа.
Первым шагом мы удалили нерелевантные символы, слова и посты. Из исходных данных мы убрали всё, что не несет дополнительной информации — пунктуацию, теги пользователей, числа, латинские слова, ссылки, служебные символы. Также мы убрали посты, которые содержали меньше 40 символов: часто это были неинформативные записи, по которым невозможно было определить мнение автора без полного контекста.
Убираем служебные символы (теги пользователей в квадратных скобках) при помощи регулярных выражений:
Убираем пропуски в столбце [‘text’]:
Убираем слишком короткие неинформативные посты до 40 символов:
Убираем знаки препинания, числа, лишние пробелы, латинские слова. Также подготовим список стоп-слов русского языка для дальнейшей очистки текстов. Стоп-слова – это часто повторяющиеся слова, которые не несут смысла для модели, так как повторяются во всех текстах: предлоги, союзы, междометия. В некоторых библиотеках уже есть есть готовые списки стоп-слов — мы воспользовались списком из библиотеки NLTK:
Мы убрали также посты, которые определили как нерелевантные на этапе ручной разметки. Мы сделали это простым исключением строк, которые содержат ключевые слова «кошка», «собака», «родословная», «передержка» и «турагенство», «все включено».
Очищенные тексты мы сохранили отдельно. Пример такого текста:
Подготовка данных
В русском языке одно и тоже слово может иметь множество форм — число, падеж, род. Такое многообразие мешает поиску самых популярных слов, и, соответственно, изучению контекста массива сообщений. Перед тем, как применять машинное обучение, мы привели все слова к начальному виду. Для этого мы использовали следующие операции:
Исходная строка: | @id197263123, За побочки и смерти людей после этой непроверенной жижи! |
Очистили от знаков препинания, латиницы и лишних символов: | За побочки смерти людей после этой непроверенной жижи |
Привели к нижнему регистру: | за побочки смерти людей после этой непроверенной жижи |
Разбили предложение на слова (это называется токенизация): | за, побочки, смерти, людей, после, этой, непроверенной, жижи |
Привели все слова к начальной форме (лемматизация): | за, побочки, смерть, люди, после, это, непроверенный, жижа |
Каждое сообщение из столбца ‘text_prep’ мы разбили на слова (токенизировали) при помощи функции word_tokenize из библиотеки NLTK, отфильтровали по списку стоп-слов и собрали заново в строки в столбце ‘text_sw’:
Вот пример текста из столбца ‘text_sw’:
Для лемматизации мы использовали русскоязычную библиотеку PyMystem3 от Яндекса. Лемматизированные тексты сохранили в новый столбец [‘text-lemm’].
Сравните написание слов в столбцах [‘text_sw’] и [‘text_lemm’]:
Обучение модели
После первых двух этапов мы получили набор токенов для каждого сообщения, а также результаты ручной классификации 10 тысяч постов. Все сообщения получили один из следующих классов:
0 | антивакцинационный |
1 | провакцинационный |
2 | нейтральный |
3 | нерелевантный |
Для оптимального результата мы тестировали работу нескольких алгоритмов классификации. Подробнее рассмотрим два из них — Naive Bayes Classifier и Logistic Regression.
Вместе с каждым из алгоритмов мы использовали CountVectorizer и TfidfTransformer из библиотеки scikit-learn для того, чтобы представить текст в понятном для алгоритмов виде, а также тестировали два сценария классификации: с выделением трех классов сообщений (против вакцин, за вакцины и остальные) и двух классов сообщений (против вакцин и остальные). Ни один из результатов разбиения на три класса не оказался приемлемым, поэтому мы рассмотрим только результаты разбиения на два класса.
Перед началом обучения модели мы выделили в отдельные переменные признаки — X — и целевую переменную — Y. Признаки — это данные, которые нужны модели для того, чтобы научиться предсказывать значения. В нашем случае это столбец [‘text_lemm’], в котором хранятся приведенные к начальной форме тексты. Целевая переменная — это то, что мы хотим получить в результате работы модели, то есть, класс поста: написан он противником вакцинации или нет.
Сообщения, которые мы разметили вручную, мы разделили на обучающую и тестовую выборки. Обучающая выборка нужна для того, чтобы научить модель угадывать отношение автора поста к вакцинации, а тестовая — для того, чтобы проверить, насколько адекватно модель её угадывает.
Далее рассмотрим несколько алгоритмов машинного обучения и несколько вариантов подготовки данных для них.
Naive Bayes Classifier (Наивный Байесовский Классификатор)
Задали алгоритм для модели (по умолчанию векторизатор CountVectorizer работает с униграммами — отдельными словами):
Затем обучили модель и воспользовались уже обученной моделью, чтобы сделать прогноз на тестовой выборке:
Посчитали метрики качества модели:
Видим, что модель плохо себя показывает на «анти»-постах: показатель recall равен 0,37. Это значит, что из всех постов, которые были вручную размечены как «антивакцинационные», она смогла определить правильно всего 37%.
Эту же модель мы протестировали и для биграмм — сочетаний из двух слов. Такие сочетания позволяют сохранить связь между словами. Например, из текста «никто не может заставить человек делать прививки», можно получить следующие биграммы: «никто не», «не может», «может заставить», «заставить человек», «человек делать», «делать прививки».
Видим, что качество модели даже ухудшилось по сравнению с первым вариантом, показатель recall опустился до 20%.
2. Logistic Regression (Логистическая регрессия).
Посмотрим на результаты модели Logistic Regression (Логистической регрессии).
Униграммы:
Видим, что логистическая регрессия показала себя гораздо лучше Наивного Баейсовского классификатора на униграммах. Посмотрим, каких результатов нам удалось добиться при тестировании с точностью до биграмм.
При тестировании модели Логистической Регрессии с точностью до биграмм мы получили показатель Accuracy (Точность) = 0.75 — это означает, что в 75% случаев модель смогла верно распределить посты на группы в сравнении с ручной разметкой.
Параметр Precision отвечает на вопрос: какая часть текстов, которые были классифицированы в определенную группу, действительно принадлежит этой группе. В нашем случае 67% текстов, которые модель определила как антивакционные действительно являются антивакцинационными, и 81% «остальных» (не антивакционных) текстов действительно являются не антивакцинационными.
По параметру Recall можно оценить сколько постов из тех, которые действительно являются антивакцинационными, наша модель смогла определить как таковые. В целом и здесь мы получили достаточно хорошие результаты — модель определила 71% антивакцинационных и 78% не антивакционных постов.
В целом модель логистической регрессии с векторизацией по биграммам показала достаточно хорошие результаты, и именно её мы использовали для разметки нашего основного датасета, состоящего из 3 млн постов.
Выводы
На выборке, которую мы просмотрели вручную, у модели получилось достаточно хорошо угадать к какой группе относится пост, даже в не самых очевидных случаях.
Примеры правильно размеченных постов:
text | class |
Он поймал коронавирус? Ну всё, теперь мы в безопасности, уносите вакцины
Источник: https://habr.com/ru/post/593427/
Поделиться ссылкой:
Интересные статьиИнтересные статьи
Хорошая гипотеза притягивает ум математика. Она говорит о чем-то сложном и глубоком точно и лаконично, требуя доказательства или опровержения. Перед хорошей формулой тяжело устоять.
...
Все мы хотим быть в курсе происходящего поэтому часть своего времени тратим на чтение новостей, и сейчас все чаще новости приходят не из новостных сайтов или газет, а из ...
Все «за» и «против» 1С-Битрикс, какие есть альтернативы и что выгоднее знать разработчику?
Читать далее
В обновлении «Сидней» Битрикс выпустил новый продукт в составе Битрикс24: магазины. Теперь в любом портале можно создать не только лендинг или многостраничный сайт, но даже интернет-магазин. С корзино...
Если Вы используете в своих проектах инфоблоки 2.0 и таблицы InnoDB, то есть шанс в один прекрасный момент столкнуться с ошибкой MySQL «SQL Error (1118): Row size too large. The maximum row si...
|