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

«Не время умирать» (2021) Анализ рецензий на фильм с помощью НЛП

Как и многим людям, если вы тоже поклонник фильмов о Бонде, вам обязательно понравится набор данных, с которым мы собираемся работать. Это обзоры фанатов последней части франшизы под названием Не время умирать, выпущенной в 2021 году. Набор данных — это не какой-то усовершенствованный готовый файл, который мы собираемся позаимствовать у одного из эти популярные платформы Data Science. Скорее, выбрав органический путь, мы возьмем эти данные из IMDb. Позвольте мне рассказать вам, как это работает.

Всякий раз, когда мы посещаем веб-страницу, мы видим воочию лишь совокупность текстов, изображений, видео и ссылок, содержащихся внутри “HTML-тегов”. Эти теги вложены друг в друга, чтобы придать веб-странице более структурированный вид. Итак, веб-страница — это всего лишь набор тегов, содержащих некоторую информацию, и, принимая во внимание только ту информацию, которая общедоступна, будет просто вопрос поиска правильных теговкоторые содержат нужные нам данные и получают их с веб-страницы посредством HTTP-запроса. (Если вы новичок в концепции HTTP-запросов, прочтите эту статью, чтобы быстрее освоиться.) Давайте посмотрим на код Python:

from bs4 import BeautifulSoup
import requests

response = requests.request('GET','https://www.imdb.com/title/tt2382320/reviews?sort=curated&dir=desc&ratingFilter=0')
soup = BeautifulSoup(response.content,'html5lib')

#<div class="text show-more__control"></div>

table = soup.find('div', attrs = {'class':'lister-list'})
review_list = []
for i in table.findAll('div',attrs={'class':'text show-more__control'}):
  print(i.contents)
  review_list.append(i)

Давайте разберем это:

  • Мы использовали две важные библиотеки requests и bs4: первая используется для выполнения реального HTTP-запроса, а вторая — для очистки данных с помощью парсера.
  • Мы отправляем HTTP-запрос с помощью функции requests.request и в качестве аргументов передаем используемый метод, в данном случае GET, а затем url веб-страницы. Это сохраняется в переменной response.
  • Как только мы получим ответ, мы передаем его содержимое (примечание: reponse.content) в BeautifulSoup, а также передаем аргумент, указывающий тип используемого синтаксического анализатора, здесь используется парсер 'html5lib'. Опять же, конечный результат сохраняется в переменной soup.
  • Библиотека Beautiful Soup имеет множество функций, которые вы можете изучить здесь, однако для этой демонстрации мы собираемся использовать только метод find, который принимает два аргумента: вид тега, который мы хотим извлечь из него его атрибуты и получить всю содержащуюся в них информацию. По сути, это помогает найти один тег на всей веб-странице и получить все, что вложено в него. Возвращаемое значение здесь сохраняется в переменной table.
  • Посмотрите на иллюстрацию ниже, чтобы лучше понять, как на самом деле выглядит веб-страница в HTML:
<div class='lister-list'> 

  <div class='text show-more__control'> Review 1 </div>
  <div class='text show-more__control'> Review 2 </div>
  <div class='text show-more__control'> Review 3 </div>

</div>
  • До этого шага все, что мы пытаемся сделать, — это углубиться в дебри тегов, чтобы найти контейнер lister-list и получить всю информацию, вложенную в него. т. е. все теги test show_more__control и текст внутри них.
  • Мы используем функцию table.findAll() для получения каждого тега test show_more__control и сохранения его текста в списке с именем review_list.

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

Подготавливаем данные для анализа

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

import pandas as pd
data = pd.DataFrame(review_list,columns=['Review'])

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

После этого шага я заметил, что мои обзоры, хотя и в текстовой форме, все еще содержали эти надоедливые маленькие теги <div> и <br/>. Это вредно для нашего анализа, поскольку ни мы, ни наша модель не можем извлечь из них смысла. Итак, давайте запустим еще одно преобразование, используя приведенный ниже код:

for x in data['Review']:
  x = x.replace("<div class=\"text show-more__control\">","")
  x = x.replace("<br/>","")
  x = x.replace("</div>","")
  temp_list.append(x)

data['cleaned_text'] = temp_list

Здесь мы в основном удаляем любой из этих тегов <div class=\”text show-more__control\”>, <br/> и </div>, если они встречаются, для каждой строки в нашем фрейме данных. Обратите внимание, что удаление здесь — это просто замена, не имеющая никакой ценности. Кроме того, replace — это просто функция манипулирования строками Python.

Если задуматься, люди, написавшие эти обзоры, такие же, как вы и я, и о, разве мы не любим украшать наш текст смайликами, такими как эти «:) :( :D :’D :’( »? Да. Но опять же, модель не понимает эти символы, и они только мешают нашим усилиям, давайте избавимся от них с помощью кода ниже:

import re
temp = []

for txt in data["cleaned_text"]:
    temp.append(re.sub("[^a-zA-Z \n]",r"",txt))

data["cleaned_text"] = temp

Здесь происходит то, что мы импортировали библиотеку RegEx Python, import re предназначена именно для этого. Далее мы берем пустой список с именем temp. После этого мы перебираем каждый обзор и с помощью регулярного выражения находим все, что не является алфавитом [^a-zA-Z \n], и удаляем его (опять же, заменяя ничем). Каждый отзыв добавляется в наш список temp. Наконец, мы вносим изменения в наш data['cleaned_text'] с помощью отфильтрованных данных.

Для простоты и в качестве стандартной процедуры давайте также преобразуем весь наш текст в нижний регистр:

data["cleaned_text"] = data["cleaned_text"].apply(lambda x: str(x).lower())

Используя функцию apply(), мы перебираем каждый отзыв и определяемую нами функцию lambda, изменяя каждый отзыв на нижний регистр. Наконец, вносим последние изменения в исходный столбец cleaned_text. Если вы поняли все операции, которые мы проделали до сих пор, угадайте, что? у тебя отлично получается! потому что мы закончили с преобразованиями данных и теперь пришло время для хороших вещей.

Анализ настроений в отзывах с помощью VADER

Возможно, некоторые головы повернутся, услышав имя ВЕЙДЕР! Я говорю о Дарте Вейдере? он здесь? бегать!!! не совсем, ребята, вы можете расслабиться. VADER означает Valence Aware Dictionary and Sentiment Reasoner (GitHub).

VADER (Valence Aware Dictionary and Sentiment Reasoner) – это инструмент анализа настроений на основе словаря и правил, который специально настроен на чувства, выраженные в социальных сетях. Его исходный код полностью открыт под лицензией [MIT License]. Для получения дополнительной информации прочитайте статью: VADER: экономная модель, основанная на правилах, для анализа тональности текста в социальных сетях (авторы: Си Джей Хатто и Эрик Гилберт) Восьмая международная конференция по блогам и социальным сетям (ICWSM-14). Анн-Арбор, Мичиган, июнь 2014 г.».

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

from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer

temp_list = []
sia = SentimentIntensityAnalyzer()

def sentiment_scores(sentence):

    
    sentiment_dict = sia.polarity_scores(sentence)

    print("Overall sentiment dictionary is : ", sentiment_dict)
    print("sentence was rated as ", sentiment_dict['neg']*100, "% Negative")
    print("sentence was rated as ", sentiment_dict['neu']*100, "% Neutral")
    print("sentence was rated as ", sentiment_dict['pos']*100, "% Positive")
    print("Sentence Overall Rated As", end = " ")

    # decide sentiment as positive, negative and neutral
    if sentiment_dict['compound'] >= 0.05 :
        print("Positive")
        temp_list.append("Positive")

    elif sentiment_dict['compound'] <= - 0.05 :
        print("Negative")
        temp_list.append("Negative")

    else :
        print("Neutral")
        temp_list.append("Neutral")


data["cleaned_text"].apply(sentiment_scores)
data['sentiment'] = temp_list

Позвольте мне объяснить, что происходит:

  • Мы импортируем SentimentIntensityAnalyzer из vaderSentiment. Если вы видите здесь ошибку, возможно, это связано с тем, что VADER не установлен на вашем компьютере. Используйте этот код !pip install vaderSentiment, чтобы исправить ситуацию.
  • Далее мы создаем пустой список с именем temp_list и инициализируем анализатор с помощью переменной sia.
  • После этого мы создали функцию sentiment_scores, которая принимает предложение и выполняет следующие операции:
  • - — — а) Передайте предложение через функцию polarity_scores, чтобы получить оценки в формате словаря Python.
  • - — — б) Распечатайте баллы для каждого предложения в процентном формате, используя sentiment_dict[‘neg’]*100 для всех положительных, отрицательных и нейтральных настроений.
  • - — — c) Вычислите, является ли общее предложение положительным, т. е. sentiment_dict[‘compound’] > 0.05 (поскольку составная оценка выражается в вероятностных терминах), или отрицательным sentiment_dict[‘compound’]<= -0.05, или оно нейтрально, ни одно из двух условия верные.
  • Это повторяется для каждого отзыва, и более того, мы сохраняем окончательное мнение (положительное, отрицательное или нейтральное) в файле temp_list.
  • Далее, data[‘cleaned_text’].apply(sentiment_scores) — это просто удобный способ убедиться, что функция sentiment_scores выполняется для каждой строки в столбце cleaned_text.
  • Наконец, мы создаем новый столбец с именем sentiment и заполняем его данными из нашего temp_list.

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

Что дальше?

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

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

Я надеюсь, что вам понравилось читать эту статью. Для меня это означало бы МИР, если бы вы могли выразить свою признательность через аплодисменты, поделиться и подписаться на автора. Это помогает мне мотивировать донести до вас ценный контент.

П.С. Вы можете нажимать на кнопку хлопка столько раз, сколько захотите, количество будет увеличиваться!

Следуйте за мной на GitHub и LinkedIn.

Увидимся в следующий раз и спасибо за чтение!