Создайте надежную основу, выполнив простые шаги

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

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

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

Итак, давайте начнем с простого вопроса: что такое анализ настроений?

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

 Feature: the string representing the input text Target: the text’s polarity (0 or 1)

Но в этой задаче есть что-то необычное: единственная функция, с которой мы работаем, не является числовой. А чтобы обучить классификатор машинного / глубокого обучения, нам нужны числовые функции.

К сожалению, мы даже не можем использовать одноразовое кодирование, как это сделали бы для категориальной функции (например, функции color со значениями red, green , blue и т. Д.), Потому что тексты не категории, и, вероятно, нет текста, который бы в точности совпадал с другим. Использование однократного кодирования в этом случае просто приведет к заучиванию «наизусть» полярности настроений каждого текста в наборе обучающих данных. Итак, как мы можем продолжить?

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

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

  • Этап предварительной обработки, чтобы текст был чище и легче обрабатывался.
  • И шаг векторизации для преобразования этих текстов в числовые векторы.

Давайте нырнем!

Предварительная обработка

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

Text: This is a cat.  -->  Word Sequence: [this, is, a, cat]

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

Более того, реальный текст часто бывает «грязным». Поскольку этот текст обычно автоматически извлекается из Интернета, некоторый код HTML может смешаться с фактическим текстом. Поэтому нам также необходимо немного привести в порядок эти тексты, чтобы избежать использования кодовых слов HTML в наших последовательностях слов. Например :

<div>This is not a sentence.<\div> --> [this, is, not, a, sentence]

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

Используя Python 3, мы можем написать функцию предварительной обработки, которая берет блок текста и затем выводит очищенную версию этого текста. Но прежде чем мы это сделаем, давайте быстро поговорим об очень удобной вещи, называемой регулярными выражениями.

Регулярное выражение (или регулярное выражение) - это последовательность символов, представляющая шаблон поиска. Каждый персонаж имеет значение; например, . означает any character that isn't the newline character: '\n'. Эти символы часто сочетаются с квантификаторами, такими как *, что означает zero or more. Комбинируя эти два символа, мы можем создать регулярное выражение, которое ищет выражение в форме '<' + 'zero or more' of 'anything but \n' + '>'. Это регулярное выражение <.*?>. Здесь символ ? указывает на нежадный поиск:

Input string: <a>bcd>
Difference between greedy and non-greedy search :
greedy: <.*>   -->   <a>bcd>
non-greedy: <.*?>   -->   <a>

Регулярные выражения очень полезны для обработки строк. Например, регулярное выражение <.*?>, которое мы представили ранее, можно использовать для обнаружения и удаления тегов HTML. Но мы также будем использовать другое регулярное выражение, такое как \', чтобы удалить символ ', чтобы слова типа that's стали thats вместо двух отдельных слов that и s.

Используя re, Python библиотеку для регулярных выражений, мы пишем нашу функцию предварительной обработки:

Векторизация

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

Самый простой метод векторизации текста - это мешок слов (BOW). Он начинается со списка слов, называемого словарем (часто это все слова, встречающиеся в обучающих данных). Затем, учитывая введенный текст, он выводит числовой вектор, который является просто вектором количества слов для каждого слова словаря. Например :

Training texts: ["This is a good cat", "This is a bad day"]
=> vocabulary: [this, cat, day, is, good, a, bad]
New text: "This day is a good day"   -->   [1, 0, 2, 1, 1, 1, 0]

Как мы видим, значения для «cat» и «bad» равны 0, поскольку этих слов нет в исходном тексте.

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

Чтобы использовать векторизацию BOW в Python, мы можем полагаться на CountVectorizer из библиотеки scikit-learn. Помимо векторизации, это также позволит нам удалять стоп-слова (т. Е. Очень распространенные слова, не имеющие особого значения, например this, that или the). scikit-learn имеет встроенный список стоп-слов, которые можно игнорировать, передав stop_words="english" векторизатору. Более того, мы можем передать нашу пользовательскую функцию предварительной обработки из более ранней версии, чтобы автоматически очищать текст перед его векторизацией.

Пример использования: обзоры фильмов IMDb

Давайте практиковаться! Набор данных обзоров фильмов IMDb представляет собой набор из 50 000 обзоров, половина из которых положительные, а другая половина - отрицательные. Этот набор данных широко используется в тестах для анализа настроений, что делает его удобным способом оценки нашей собственной производительности по сравнению с существующими моделями.

Получение набора данных

Набор данных доступен в Интернете и может быть либо напрямую загружен с веб-сайта Стэнфорда, либо получен путем запуска в терминале (Linux):

wget http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz

Затем нам нужно извлечь загруженные файлы. Вы можете еще раз сделать это вручную или запустив:

tar -zxvf aclImdb_v1.tar.gz

Теперь у нас есть папка с данными под названием aclImdb. Оттуда мы можем использовать следующую функцию для загрузки наборов обучающих / тестовых данных из IMDb:

Давайте обучим классификатор анализа настроений. Следует иметь в виду, что векторы признаков, которые возникают в результате BOW, обычно очень большие (в данном случае 80 000-мерные векторы). Поэтому нам нужно использовать простые алгоритмы, которые эффективны для большого количества функций (например, наивный байесовский, линейный SVM или логистическая регрессия). Давайте, например, обучим линейный классификатор SVM.

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

Как видите, выполнив несколько очень простых шагов и используя простую линейную модель, мы смогли достичь точности 83,68% для набора данных IMDb. Чтобы понять, насколько это хорошо, недавняя современная модель может получить точность около 95%. Так что это совсем неплохо, но есть еще кое-что для улучшения.

Улучшение текущей модели

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

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

Чтобы решить эту проблему, мы можем использовать Term Frequency (TF) вместо количества слов и разделить количество вхождений на длину последовательности. Мы также можем уменьшить эти частоты, чтобы слова, которые встречаются постоянно (например, связанные с темой или стоп-слова), имели более низкие значения. Этот коэффициент масштабирования называется обратной частотой документа (IDF) и равен логарифму частоты обратного слова документа.

В совокупности эти новые функции называются функциями TF-IDF. Итак, в итоге:

На практике мы можем обучить новую линейную SVM функциям TF-IDF, просто заменив CountVectorizer на TfIdfVectorizer. Это дает точность 86,64%, что на 2% больше, чем при использовании функций BOW.

Второе, что мы можем сделать для дальнейшего улучшения нашей модели, - это придать ей больше контекста. Фактически, рассмотрение каждого слова по отдельности может привести к некоторым ошибкам. Например, если слово good встречается в тексте, мы, естественно, склонны говорить, что этот текст положительный, даже если на самом деле встречается выражение not good. Этих ошибок легко избежать, если ввести N-граммы.

N-грамма - это набор из N последовательных слов (например, very good [2 грамма] и not good at all [4 грамма]). Используя N-граммы, мы получаем более богатые последовательности слов.

Например, с N = 2:

This is a cat. --> [this, is, a, cat, (this, is), (is, a), (a, cat)]

На практике включить N-граммы в наш векторизатор TF-IDF так же просто, как указать дополнительный параметр ngram_range=(1, N). Вообще говоря, использование биграмм улучшает производительность, поскольку мы предоставляем модели больше контекста, в то время как N-граммы более высокого порядка имеют менее очевидные эффекты.

Сложив все это вместе, мы получаем еще более высокий показатель точности - 88,66%, что является еще одним улучшением на 2% по сравнению с последней версией модели.

В этом посте мы увидели, как создать надежную основу для классификации текста, выполнив несколько простых шагов:

  • Во-первых, это этап предварительной обработки, который имеет решающее значение, но не должен быть слишком сложным. Фактически, единственное, что нам нужно сделать, это удалить знаки препинания и преобразовать все в нижний регистр.
  • Затем следует этап векторизации, на котором создаются числовые признаки для классификатора. Для этого мы использовали TF-IDF, простой метод векторизации, который заключается в вычислении частот слов и их уменьшении для слишком общих слов.
  • Наконец, для дополнительного контекста мы предоставляем модели N-граммы, то есть N-кортежи следующих друг за другом слов. Применив этот метод к набору данных IMDB Movie Reviews, нам удалось обучить классификатор анализа настроений, который набирает около 89% (что всего на 6% от современного состояния).

Что дальше?

Возможности, возникающие при использовании методов векторизации на основе подсчета, таких как TF-IDF, имеют некоторые недостатки. Например:

  • Они не учитывают положение слова и контекст (несмотря на использование N-граммов, что является лишь быстрым решением).
  • Векторы слов TF-IDF, как правило, очень многомерны (особенности 1M при использовании биграмм).
  • Они не могут улавливать семантику.

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