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

Допустим, однажды у вас появилась идея — вы собираетесь классифицировать все сообщения чата в slack вашего проекта на релевантные/нерелевантные какой-то проблеме. Может случиться так, что существует общий канал обработки данных, предназначенный для различных проблем, таких как проблемы, связанные с хаупом, вопросы по коду Spark scala или даже UI/UX для информационных панелей.

В такой чат-группе может ежедневно поступать огромное количество записей. Да, одно из возможных решений — разделить этот канал на несколько, но в какой-то момент это станет кошмаром — просмотреть все истории и найти полную историю по одной теме. Обсуждение может начинаться с обсуждения общей архитектуры, которое перенаправляется в канал эксплуатации и каналы разработки для межгрупповых обсуждений, а затем переходит в каналы QA/UAT.

Перед длинными выходными вы начинаете с того, что копаетесь в проблемном пространстве, делаете вялого бота, который бы собирал информацию, и делаете полную историю сообщений по одной истории. Интеграция со slack API достаточно проста, и эта проблема решается вами всего за несколько часов, и… у вас есть куча записей ‹Ti, Mi›, где Ti — временная метка сообщения, а Mi — текст, отправленный человеком. В нашем случае нас меньше интересуют автор и канал, хотя они тоже могут быть важны.

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

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

Стемминг реализован и известен большинству тех, кто хоть раз в жизни пробовал работать с текстовыми данными. Stemming пытается перевести слово в его нормальную форму, удаляя любые суффиксы и префиксы. Например, «вожделение» будет преобразовано в «вожделен», для тех, кто не знает русский результат стемпинга — не имеет значения даже для русскоязычных людей, не только для вас. Но это резко уменьшит размер словаря корпуса, уменьшит размерность и, наконец, улучшит производительность и точность.

И да, теперь вы немного разбираетесь в этой теме, стоит ли нам копаться в существующих библиотеках или алгоритмах для стемминга или лемматизации — я думаю, что нет. В Интернете есть ряд статей, в которых подробно описывается, как это работает и как лучше всего реализовать. Вместо этого давайте посмотрим на результаты, которые я получаю — наивный способ, когда необработанный текст, отправленный в классификатор, приносит мне: 0,679, а текст с основой: 0,682.

ВАУ! Всего 0,003, но этот шаг уменьшил объем памяти, необходимый для процесса обучения, сократил время, которое требуется, и повысил производительность.

PS: Для тех, кому может быть интересно, мой пайплайн выглядит так (текст) -> tfidf -> NaiveBayes.