Классификация тональности текстовых данных обзора ресторана с использованием векторов TF-IDF

В этом посте показано, как можно использовать модель TF-IDF для мультиклассовой классификации текста. Набор данных обзора Yelp Restaurant будет использоваться для классификации настроений с использованием модели TF-IDF. В последнем посте для решения той же задачи использовалась модель BOW (Bag of Words). TF-IDF - это не что иное, как модель мешка слов, у которой есть способ взвешивать токены или слова, которые часто встречаются в остальных документах набора данных.

Это имеет смысл там, где слова, встречающиеся почти в большинстве документов, не могут помочь отличить данный документ от других. Будет ли это лучше, чем BOW для классификации настроений? Это нужно учитывать и понимать, исходя из проблемы и имеющихся данных. Если люди используют одинаковый набор слов для выражения положительных / отрицательных настроений, то, скорее всего, частота этих слов во всем наборе данных будет больше, и в этом случае это не обязательно даст лучшие результаты, чем BOW. Давайте посмотрим, как это работает в наборе данных Yelp Review. Некоторые шаги, такие как загрузка данных, изучение и предварительная обработка данных, будут похожи на мой предыдущий пост.

Загрузите данные

Набор данных для обзора ресторанов Yelp можно скачать с их сайта, а формат представленных данных - JSON. Предоставленные данные на самом деле не в правильном формате json, читаемом для python. Каждая строка является словарем, но для того, чтобы это был допустимый формат json, квадратная скобка должна быть в начале и в конце файла с добавлением , в конце каждой строки. Определите INPUT_FOLDER как путь к папке в вашем локальном каталоге, где находится файл yelp review.json. Объявите OUTPUT_FOLDER как путь, куда вы хотите записать вывод следующей функции. Загрузка данных json и запись первых 100000 строк выполняется с помощью следующей функции:

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

Изучение данных

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

Вывод:

После того, как данные доступны, выполняется сопоставление звездочек с настроениями и строится распределение для каждого настроения.

Как только это будет сделано, проверяется количество строк для каждого настроения. Классы настроений следующие:

  1. Положительных: 1
  2. Отрицательный: -1
  3. Нейтрально: 0

Количество строк неравномерно распределяется по этим трем настроениям. В этом посте проблема несбалансированных классов не рассматривается, поэтому написана простая функция для получения нескольких верхних записей для каждого настроения. В этом примере top_n равно 10000, что означает, что всего будет взято 30 000 записей.

Вывод:

Как предварительно обработать текстовые данные?

Предварительная обработка включает в себя множество шагов, таких как токенизация, удаление стоп-слов, стемминг / лемматизация и т. Д. Эти обычно используемые методы были подробно объяснены в моем предыдущем сообщении BOW. Здесь объясняются только необходимые шаги на следующем этапе.

Зачем нужна предварительная обработка этого текста? - Не вся информация полезна при прогнозировании или классификации. Уменьшение количества слов уменьшит размер ввода вашей модели. Язык написан так, что он содержит много грамматической информации. Таким образом, при преобразовании в числовой формат специфичные для слова характеристики, такие как использование заглавных букв, знаки препинания, суффиксы / префиксы и т. Д., Являются избыточными. Очистка данных таким образом, чтобы похожие слова отображались в одно слово, и удаление грамматической информации из текста может значительно сократить словарный запас. Какие методы применять, а какие пропустить, зависит от решаемой проблемы.

1. Удаление стоп-слов

Стоп-слова - это слова, которые обычно используются и удаляются из предложения в качестве предварительного шага в различных задачах обработки естественного языка (NLP). Примеры стоп-слов: 'a', 'an', 'the', 'this', 'not' и т. Д. Каждый инструмент использует немного другой набор стоп-слов, который он удаляет, но этого метода избегают в случаях, когда фраза структура имеет значение, как и в случае с анализом настроений.

Пример удаления стоп-слов:

Вывод:

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

2. Токенизация

Токенизация - это процесс, в котором предложение / текст разбивается на массив слов, называемых токенами. Это помогает выполнять преобразования для каждого слова отдельно, а также требуется для преобразования слов в числа. Существуют разные способы токенизации. Я объяснил эти способы в моем предыдущем посте в разделе Токенизация, так что, если вам интересно, вы можете это проверить.

simple_preprocess Gensim позволяет преобразовывать текст в нижний регистр и удалять знаки препинания. Он также имеет параметры длины min и max, которые помогают отфильтровать редкие слова и наиболее часто встречающиеся слова, которые попадают в этот диапазон длин.

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

Вывод:

3. Стебель

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

Для стемминга используются разные алгоритмы. PorterStammer (1979), LancasterStammer (1990) и SnowballStemmer (может добавлять собственные правила). Для реализации этих алгоритмов стемминга можно использовать пакет NLTK или Gensim. Lancaster немного медленнее, чем Porter, поэтому мы можем использовать его в соответствии с размером и требуемым временем отклика. Стеммер Snowball - это немного улучшенная версия стеммера Porter, которую обычно предпочитают последнему. Не очень ясно, какой из них даст точные результаты, поэтому нужно экспериментировать с разными методами и выбирать тот, который дает лучшие результаты. В этом примере используется Porter Stemmer, который прост и быстр. Следующий код показывает, как реализовать стемминг в фрейме данных и создать новый столбец stemmed_tokens:

Вывод:

Строительный словарь

Каждое уникальное слово будет идентифицировано уникальным идентификатором в объекте словаря. Это необходимо создать для создания представлений текстов. С его помощью создается корпус Bag of Words, который потребуется для построения модели TF-IDF. Словарь создается по списку слов. Предложения / документы и т. Д. Могут быть преобразованы в список слов и затем переданы в corpora.Dictionary в качестве параметра. Давайте создадим словарь для данных отзывов с помощью stemmed_tokens:

Вывод:

Разделение на обучающие и тестовые наборы:

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

  • Данные обучения (подмножество данных для обучения модели машинного обучения) ~ 70%
  • Тестовые данные (подмножество данных для тестирования модели машинного обучения, обученной на основе данных поезда) ~ 30%

Постарайтесь сбалансировать количество классов в обоих наборах, чтобы результаты не были предвзятыми или одной из причин недостаточного обучения модели. Это важная часть модели машинного обучения. В реальных проблемах бывают случаи несбалансированных классов, которые требуют использования таких методов, как передискретизация класса меньшинства, недостаточная выборка класса большинства (функция передискретизации из пакета scikit-learn или создание синтетических образцов с использованием функциональности SMOTE в пакете Imblearn.

В этом случае данные разделяются на две части: обучение и тестирование, при этом 70% находятся в обучении, а 30% - в тесте. При разбиении лучше иметь равное распределение классов как в обучающих, так и в тестовых данных. Здесь используется функция train_test_split из пакета scikit-learn.

Вывод:

Как видно из вышеприведенного вывода, данные распределяются для каждого класса пропорционально. Распечатывается количество строк для каждого настроения в поездке и тесте.

Создание модели TFIDF

Tf-IDF вычисляется путем умножения локального компонента, такого как частота термина (TF), на глобальный компонент, то есть обратной частоты документа (IDF), и, при необходимости, нормализации результата до единичной длины.

Срок i в документе j с общим D документами в корпусе, а document_freq_{i} - это количество документов, в которых существует термин i. Log применяется для сглаживания вывода, например, если количество документов в корпусе слишком велико, значение IDF будет увеличиваться, и, следовательно, для снижения этого влияния на IDF применяется журнал.

weight_{i,j} = frequency_{i,j} * log_2(D / document_freq_{i})

Здесь пакет Gensim используется для получения модели TFIDF. Следующий код показывает, как получить модель TFIDF:

Создание векторов TFIDF

Когда модель будет готова, ее можно использовать для получения вектора TFIDF для каждой строки. Модель даст плотный вектор, и чтобы иметь возможность иметь одинаковую длину функций, ее следует преобразовать в разреженный вектор с помощью функции gensim.matutils.corpus2csc. Давайте сгенерируем векторы TFIDF для каждой строки данных поезда (X_train) и запишем их в файл csv. Вы можете напрямую создать это в фреймворке данных, но когда есть большой объем данных, лучше записывать в файл по мере создания вектора, и если код ломается, вы можете начать с того места, где он сломался. Следующий код записывает векторы в OUTPUT_FOLDER, определенные на первом шаге.

Вывод:

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

Модель классификации настроений при обучении с использованием векторов TFIDF

Когда векторы TFIDF готовы к обучению, мы загружаем их в фрейм данных. DecisionTreeClassifier используется здесь для классификации настроений. Классификатор дерева решений - это контролируемый алгоритм машинного обучения для классификации. В этом примере пакет scikit-learn используется для реализации класса классификатора дерева решений. Функция fit используется для согласования входных векторов признаков с настроениями в данных поезда. В следующем коде показано, как обучить классификатор векторам TFIDF.

Вывод:

Обучение работе с нашими входными данными заняло ~ 41 секунду. clf_decision_tfidf переменную теперь можно использовать для прогнозов.

Получение важных функций, влияющих на модель

Атрибут _feature_importances_ модели может использоваться для получения наиболее важных функций. Он дает ценность для каждой функции, чем больше значение, тем важнее. Ниже показаны 20 самых важных функций. Самые популярные слова, такие как «нет», «отличный», «удивительно», «худший», «люблю» и т. Д., Имеют смысл, поскольку они помогают выразить мнение. Нет существенной разницы, которая была обнаружена при использовании представления BOW (мешок слов), но некоторые из слов, такие как «ok», «it», «wa» и т. Д., По крайней мере, имеют более низкий ранг по сравнению с BOW. Нелегко увидеть разницу с меньшим количеством данных, но с большими данными вы можете обнаружить существенные различия.

Вывод:

Тестирование модели

После обучения модели ее можно протестировать на тестовом наборе данных.

Вывод:

Отчет о классификации показывает среднюю точность, которая составляет 0.55. Это хороший результат по сравнению с объемом данных, использованных для обучения. Функция predict может использоваться на объекте модели, чтобы получить прогнозируемый класс для тестовых данных. Точность для положительных и отрицательных настроений лучше, чем для нейтральных, что имеет смысл, поскольку трудно отличить нейтральные комментарии от обычно используемых слов в положительных и отрицательных настроениях.

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

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

Как всегда - Удачных экспериментов и обучения :)