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

Введение в анализ настроений

Также известный как «анализ мнений», анализ настроений относится к использованию обработки естественного языка для определения отношения, мнений и эмоций говорящего, писателя или другого субъекта в онлайн-упоминании.

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

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

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

Предпосылки

  • Базовые знания программирования:

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

  • Установленные инструменты:

Для этой программы нам потребуется установить Python на компьютер. Мы будем использовать библиотеки twitter, nltk, re, csv, time и json. Скорее всего, вам придется установить первые две библиотеки. Остальные уже идут с интерпретатором Python. Тем не менее, не помешает проверить их актуальность.

  • Концепция разделения набора данных:

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

  • Базовые знания RESTful API:

Это не критично, но может помочь. Мы будем использовать Twitter API здесь и там в коде, делая обычные вызовы API и работая с объектами JSON, которые он возвращает. В случае необходимости вы можете найти официальную документацию Twitter API здесь.

Описание процесса

Раздел A: Подготовка набора для тестирования

  • Шаг A.1: Получение учетных данных для аутентификации
  • Шаг A.2: Аутентификация нашего скрипта Python
  • Шаг A.3: Создание функции для построения тестового набора

Раздел Б. Подготовка набора для обучения

Раздел C. Предварительная обработка твитов в наборах данных

Раздел D. Наивный байесовский классификатор

  • Шаг D.1: Создание словарного запаса
  • Шаг D.2: Сопоставление твитов с нашим словарным запасом
  • Шаг D.3: Построение нашего вектора функций
  • Шаг D.4: Обучение классификатора

Раздел E. Тестирование модели

Перед тем, как мы начнем:

  • Иногда Twitter может занять несколько дней, чтобы одобрить ваше приложение для использования Twitter API. Однако обычно это занимает менее 24 часов.
  • Загрузка обучающего набора может занять более 10 часов (это будет объяснено позже).
  • Учебное пособие было взято из курса Удеми: От 0 до 1: Машинное обучение, НЛП и Python-переход к The Chase.

Раздел A: Подготовка набора для тестирования

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

Я решил начать с тестового набора, чтобы вы все разогрелись для части извлечения обучающего набора, поскольку он будет больше полагаться на API. Вот небольшой обзор того, что мы собираемся делать:

1- Зарегистрируйте приложение Twitter, чтобы получить наши собственные учетные данные.

2- Аутентифицируйте наш скрипт Python с помощью API, используя учетные данные.

3- Создайте функцию для загрузки твитов на основе ключевого слова поиска.

Регистрация приложения в Twitter имеет решающее значение, поскольку это единственный способ получить учетные данные для аутентификации. Как только мы получим наши учетные данные, мы начнем писать код. Шаг 3 - это тестовый набор. Мы будем загружать твиты на основе термина, по которому мы пытаемся проанализировать настроение.

Шаг A.1. Получение учетных данных для аутентификации

Во-первых, нам нужно посетить веб-сайт разработчика Twitter и войти в нашу учетную запись по следующей ссылке:



В правом верхнем углу нажмите кнопку «Приложения», «Создать приложение», «Применить», а затем «Продолжить», как показано ниже:

Затем мы выберем вариант «Я запрашиваю доступ для личного использования»:

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

После того, как вы сделаете свой выбор, прокрутите вниз и заполните требуемый абзац, интересующий вас. Twitter сейчас очень серьезно относится к этому (думаю, они научились на ошибках Facebook xD), поэтому убедитесь, что вы подчеркнули, что приложение является самообучающимся / академическим проектом. Выберите «Нет» для вопроса об участии правительства и нажмите «Продолжить».

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

Затем откройте свою электронную почту и подтвердите свою учетную запись разработчика Twitter, перейдя по ссылке, содержащейся в отправленном вам электронном письме. Наконец, вы получите сообщение, подобное следующему:

Все, что вы можете сделать сейчас, - это подождать несколько часов, пока заявка будет одобрена (что почти наверняка будет, если ваше объяснение не нарушает условия использования Твиттера).

Когда вы получите электронное письмо с подтверждением, щелкните ссылку для входа, содержащуюся в нем. Вы будете перенаправлены на следующую веб-страницу, где вам нужно выбрать «Создать приложение»:

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

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

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

Шаг A.2: Аутентификация нашего скрипта Python

Поскольку теперь у нас есть учетные данные для входа в систему для разработчиков Twitter (т.е. ключи API и токен доступа), мы можем приступить к аутентификации нашей программы. Сначала нам нужно импортировать библиотеку Twitter, а затем создать объект Twitter.API с учетными данными из «безопасного» места, о котором мы говорили, а именно:

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

{"created_at": "Tue Feb 12 17:48:27 +0800 2019" 'default_profile": true ............} 

В этом нет ничего сумасшедшего, кроме некоторых данных о доступе к API через вашу учетную запись Twitter. Если вы дойдете до этого, все готово.

Шаг A.3: Создание функции для создания тестового набора

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

Однако здесь есть предостережение: Twitter ограничивает количество запросов, которые вы можете делать через API, в целях безопасности. Это ограничение составляет 180 запросов на 15-минутное окно.

Это означает, что мы можем получать не более 180 твитов, используя нашу функцию поиска каждые 15 минут, что не должно быть проблемой, поскольку наш обучающий набор в любом случае не будет таким большим. Для простоты мы пока ограничим поиск до 100 твитов, не превышая допустимое количество запросов. Наша функция для поиска твитов (т.е. тестовый набор) будет:

Как и следовало ожидать, эта функция вернет список твитов, содержащих ключевое слово для поиска.

Обратите внимание, что мы объединили - в объект JSON - текст каждого твита с меткой, которая на данный момент имеет значение NULL. Это просто потому, что позже мы собираемся классифицировать каждый твит как положительный или отрицательный, чтобы определить, положительное или отрицательное отношение к поисковому запросу, на основе подсчета большинства. Вот как прагматично работает анализ настроений.

Прежде чем мы продолжим, давайте протестируем нашу функцию, добавив следующий код после тела функции:

Это должно распечатать пять твитов, содержащих ключевое слово для поиска, на Терминале вашей IDE (если вы его используете). Теперь все готово. У нас есть набор тестов, и мы можем перейти к созданию набора для обучения.

Раздел B: Подготовка обучающего набора

Обратите внимание, что пока что мы написали немного кода. Это объясняется красотой лаконичности Python в синтаксисе, а также использованием внешних программно-готовых библиотек, таких как RESTful API (Twitter API в нашем случае).

В этом разделе мы также будем использовать наш экземпляр Twitter API из последнего раздела. Однако сначала нам нужно кое-что уладить. Мы будем использовать загружаемый обучающий набор. Все твиты были помечены как положительные или отрицательные, в зависимости от содержания. Именно для этого и нужен тренировочный набор.

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

Для этой задачи мы будем использовать замечательный корпус Ника Сандерса, содержащий более 5000 классифицированных вручную твитов, что делает его довольно надежным. Здесь тоже есть одна загвоздка. Twitter не позволяет хранить твиты на личном устройстве, даже если все такие данные общедоступны. Таким образом, корпус включает ключевое слово (тему твита), метку (pos / neg) и идентификационный номер твита для каждого твита (то есть строку в нашем корпусе CSV). Вы можете получить файл, содержащий корпус, с исходного сайта или по этой ссылке личного репозитория.

Давайте вернемся немного назад. Помните ограничение Twitter API, о котором мы говорили? Это также применимо и здесь, поскольку мы будем использовать API для получения фактического текста твита через идентификационный номер каждого твита, включенный в имеющийся у нас корпус. Это означает, что для загрузки 5000 твитов нам нужно будет выполнить следующие действия:

max_number_of_requests = 180
time_window = 15 minutes = 900 seconds
Therefore, the process should follow:
Repeat until end-of-file: {
    180 requests -> (900/180) sec wait
}

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

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

  • corpusFile - это строковый путь к загруженному нами CSV-файлу Ника Сандерса. Этот файл, как упоминалось ранее, включает тему, метку и идентификатор твита.
  • tweetDataFile - это строковый путь к файлу, в котором мы хотим сохранить полные твиты. В отличие от corpusFile, этот файл будет включать текст каждого твита, а также тему, метку и идентификатор.

Далее мы начали с пустого списка corpus. Затем мы открыли файл corpusFile и добавили каждый твит из файла в список corpus.

Следующий сегмент кода имеет дело с получением текста твитов на основе идентификаторов. Мы просматриваем твиты в корпусе, вызывая API для каждого твита, чтобы получить объект Tweet.Status конкретного твита. После этого мы используем тот же объект (status) для получения связанного с ним текста и помещаем его в trainingDataSet, затем ждем (т.е. приостанавливаем выполнение) на пять минут (900/180 секунд), чтобы соблюсти ограничение на количество запросов, о котором мы говорили. .

Теперь давайте оставим нашему скрипту загрузку твитов (что займет несколько часов) после нашей последней функции. Мы можем сделать это с помощью следующего фрагмента:

Как только код завершит выполнение, ваш tweetDataFile CSV-файл будет заполнен твитами (на самом деле ~ 5000). Если вы зашли так далеко, ПОЗДРАВЛЯЕМ! - в первый раз мне потребовалось много времени, чтобы добраться сюда без проблем. Теперь мы закончили относительно скучную часть. Давайте подготовимся к предстоящему разделу.

Раздел C: Предварительная обработка твитов в наборах данных

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

Давайте поговорим о том, что важно, а что не важно в анализе настроений. Слова - самая важная часть (в той степени, о которой мы поговорим в следующем разделе). Однако, когда дело доходит до знаков препинания, вы не можете понять тональность с помощью знаков препинания. Следовательно, пунктуация не имеет значения для анализа настроений. Более того, компоненты твита, такие как изображения, видео, URL-адреса, имена пользователей, смайлики и т. Д., Не влияют на полярность (положительную или отрицательную) твита. Однако это верно только для этого приложения. Например, в другом приложении у вас может быть классификатор изображений Deep Learning, который изучает и предсказывает, обозначает ли это изображение, содержащееся в твите, что-то положительное (например, радугу) или отрицательное (например, танк). Что касается технических аспектов, то машинное обучение относится как к анализу настроений, так и к глубокому обучению. Фактически, вы можете выполнять анализ настроений с помощью глубокого обучения, но это уже история для другого дня.

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

Это была горстка, поэтому давайте разберем ее на части. Начнем с наших импортированных библиотек. re - это библиотека регулярных выражений (RegEx) Python, которая заботится о синтаксическом анализе строк и их эффективном изменении без необходимости явного перебора символов, составляющих конкретную строку. Мы также импортировали ntlk, набор инструментов Natural Processing Toolkit, который является одной из наиболее часто используемых библиотек Python. Он заботится о любой обработке, которую нам необходимо выполнить с текстом, чтобы изменить его форму или извлечь из него определенные компоненты. Конструктор класса удаляет стоп-слова. Это относительно большая тема, о которой вы можете прочитать позже, поскольку она больше связана с обработкой естественного языка и меньше связана с нашей темой.

Функция processTweets просто перебирает все входящие в нее твиты, вызывая соседнюю функцию processTweet для каждого твита в списке. Последний выполняет фактическую предварительную обработку, сначала переводя весь текст строчными буквами. Это просто потому, что почти во всех языках программирования «cAr» не интерпретируется так же, как «автомобиль». Поэтому лучше нормализовать все символы, чтобы они были строчными во всех наших данных. Во-вторых, из твита удаляются URL-адреса и имена пользователей. Это по причинам, которые мы раскрыли ранее в статье. После этого знак числа (например, #) удаляется из каждого хэштега, чтобы избежать различной обработки хэштегов. И наконец, что не менее важно, удаляются повторяющиеся символы, чтобы гарантировать, что ни одно важное слово не останется необработанным, даже если оно написано необычным образом (например, «caaaaar» становится «car»). Наконец, текст твита разбивается на слова (токенизируется), чтобы упростить его обработку на следующих этапах.

Возьмем пример. В наборе данных может присутствовать следующий твит:

"@person1 retweeted @person2: Corn has got to be the most delllllicious crop in the world!!!! #corn #thoughts..."

Наш препроцессор приведет к тому, что твит будет выглядеть так:

“AT_USER rt AT_USER corn has got to be the most delicious crop in the world corn thoughts”

И, наконец, токенизация приведет к:

{“corn”, “most”, “delicious”, “crop”, “world”, “corn”, “thoughts”}

Обратите внимание, что наш код удалил повторяющиеся символы в словах, как мы упоминали ранее (т.е. «delllllicious» стал «вкусным»). Однако он не удалил повторяющиеся слова (например, «кукуруза») из текста, а скорее сохранил их. Это связано с тем, что повторяющееся слово играет роль в определении полярности текста (как мы увидим в следующем разделе).

Мы все настроены на использование нашего класса препроцессора. Сначала мы создадим переменную, которая ссылается на нее (объект), а затем вызовем ее как в обучающем, так и в тестовом наборе, как мы обсуждали ранее:

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

Раздел D: Наивный байесовский классификатор

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

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

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

Наивный байесовский классификатор - это алгоритм классификации, основанный на теореме Байеса. Эта теорема обеспечивает способ вычисления типа или вероятности, называемой апостериорной вероятностью, при котором вероятность возникновения события A зависит от вероятностно известного фона (например, свидетельства события B). Например, если Person_X играет в теннис только тогда, когда на улице нет дождя, то, согласно байесовской статистике, вероятность того, что Person_X играет в теннис, когда нет дождя, может быть выражена как:

P(X plays | no rain) = P(no rain | X plays)*P(x plays)/P(no rain)

следуя теореме Байеса:

P(A|B) = P(B|A)*P(A)/P(B)

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

1- Создайте словарь (список слов) всех слов, находящихся в нашем наборе обучающих данных.

2- Сопоставьте содержание твита с нашим словарным запасом - слово за словом.

3- Создайте наш вектор функции слова.

4- Подключите наш вектор характеристик к наивному байесовскому классификатору.

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

Шаг D.1. Расширение словарного запаса

Словарь в Natural Language Processing - это список всех речевых сегментов, доступных для модели. В нашем случае это включает в себя все слова, присутствующие в имеющемся у нас обучающем наборе, поскольку модель может использовать их все относительно одинаково - на этом этапе, мягко говоря. Код будет выглядеть примерно так:

Это просто создание списка из all_words, который есть в обучающем наборе, с разбиением его на функции слов. Эти word_features в основном представляют собой список отдельных слов, каждое из которых имеет свою частоту (количество вхождений в наборе) как key.

Шаг D.2. Соответствие твитов нашему словарю

Этот шаг очень важен, так как мы пройдемся по всем словам в нашем обучающем наборе (то есть в нашем списке word_features), сравнивая каждое слово с текущим твитом, связывая число со следующим словом:

label 1 (true): if word in vocabulary is resident in tweet
label 0 (false): if word in vocabulary is not resident in tweet

Это довольно просто кодировать:

Учитывая последний фрагмент, для каждого слова в word_features у нас будет ключ JSON «содержит слово X», где X - это слово. Каждый из них будет иметь значение True / False, в соответствии с тем, что мы говорили ранее о ярлыках - True для «присутствует» и False для «отсутствует».

Шаг D.3. Создание вектора функций

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

Встроенная функция NTLK apply_features выполняет фактическое извлечение функций из наших списков. Наш последний вектор признаков - trainingFeatures.

Шаг D.4. Обучение классификатора

Мы наконец подошли к самой важной - и, по иронии, самой короткой - части нашей задачи. Благодаря NLTK нам потребуется только вызов функции для обучения модели как наивного байесовского классификатора, поскольку последний встроен в библиотеку:

Мы почти закончили! Все, что нам осталось, это запустить обучающий код классификатора (т.е. nltk.NaiveBayesClassifier.train()) и протестировать его. Обратите внимание, что выполнение этого кода может занять несколько минут.

Раздел E: Тестирование модели

Момент истины! Давайте закончим нашу работу, запустив классификатор (например, NBayesClassifier) для 100 твитов, которые мы загрузили из Twitter, в соответствии с нашим поисковым запросом и получив большинство голосов меток, возвращенных классификатором, а затем выведем общий положительный или отрицательный процент (т.е. оценка) твитов. Это тоже будет очень просто:

Вот и все! Поздравляю. Вы создали программу Python для анализа настроений в Twitter. Обратите внимание, что мы не касались точности (т.е. оценки модели), потому что это не наша тема на сегодня. Позже будет статья, в которой я объясню весь процесс оценки модели / гипотезы в машинном обучении. Давайте в последний раз взглянем на полный код, который мы написали для этой задачи:

Заключение

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