Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Предсказание рейтингов фильма на основе настроения рецензий.

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

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

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

Прогнозирование рейтинга фильма на основе рецензий

В этом подходе мы планируем предсказать успех фильма, оценив настроение его рецензий. Мы будем применять анализ настроения для оценки общего настроения рецензии и классифицировать фильм как “свежий” или “гнилой” на основе этого настроения.

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

Сначала прочитаем данные.

Вот код.

df_critics = pd.read_csv('rotten_tomatoes_critic_reviews_50k.csv')
df_critics.head()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes
Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Отлично, давайте начнем с предварительной обработки данных.

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

В этом наборе данных у нас нет названий фильмов и соответствующих статусов. Для этого набора данных у нас есть переменные review_content и review_type.

Поэтому мы объединим этот набор данных с нашим предыдущим, на rotten_tomatoes_link, и выберем необходимые признаки с помощью индексных скобок следующим образом.

Вот код:

df_merged = df_critics.merge(df_movie, how='inner', on=['rotten_tomatoes_link'])
df_merged = df_merged[['rotten_tomatoes_link', 'movie_title', 'review_content', 'review_type', 'tomatometer_status']]
df_merged.head()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

В этом подходе мы будем использовать только столбец review_content в качестве входной характеристики, а review_type – в качестве истинной метки.

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

df_merged = df_merged.dropna(subset=['review_content'])

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

# Plot distribution of the review
ax = df_merged.review_type.value_counts().plot(kind='bar', figsize=(12,9))
ax.bar_label(ax.containers[0])

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

Вот весь код:

df_merged = df_merged.dropna(subset=['review_content'])
# Plot distribution of the review
ax = df_merged.review_type.value_counts().plot(kind='bar', figsize=(12,9))
ax.bar_label(ax.containers[0])

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Похоже, что у нас есть проблема дисбаланса между нашими признаками.

Кроме того, у нас слишком много данных, что может снизить скорость работы алгоритма.

Поэтому сначала мы выберем 5000 записей из исходного набора данных.

df_sub = df_merged[0:5000]
review_type = pd.DataFrame(df_sub.review_type.replace(['Rotten','Fresh'],[0,1]))

Наконец, мы создадим фрейм данных, который содержит закодированные метки с содержанием обзора, используя метод concat() в Python и просмотрим первые 5 строк с помощью метода head().

df_feature_critics = pd.concat([df_sub[['review_content']]
                        ,review_type], axis=1).dropna()
df_feature_critics.head()

Вот весь код.

# Pick only 5000 entries from the original dataset
df_sub = df_merged[0:5000]

# Encode the label
review_type = pd.DataFrame(df_sub.review_type.replace(['Rotten','Fresh'],[0,1]))

# Build final DataFrame
df_feature_critics = pd.concat([df_sub[['review_content']]
                        ,review_type], axis=1).dropna()
df_feature_critics.head()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

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

X_train, X_test, y_train, y_test = train_test_split( df_feature_critics['review_content'], df_feature_critics['review_type'], test_size=0.2, random_state=42)

“Случайный лес”

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

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

Например, на основе двух отзывов “Этот фильм хороший” и “Этот фильм плохой” алгоритм создаст словарь уникальных фраз, таких как ;

Затем, основываясь на входном тексте, мы подсчитываем количество повторений каждого слова в словаре.

[“this”, “movie”, “is”, “a”, “good”, “the”, “bad”].

Например, ввод “Этот фильм – хороший фильм” приведет к вектору [1, 2, 1, 1, 1, 1, 0, 0].

Наконец, мы вводим сгенерированный вектор в нашу модель Random Forest.

Мы можем предсказать настроение отзывов и классифицировать фильм как “свежий” или “гнилой”, обучив наш классификатор Random Forest на векторизованных текстовых данных.

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

# Instantiate vectorizer class
vectorizer = CountVectorizer(min_df=1)

Далее мы собираемся преобразовать обучающие данные в векторы с помощью инстанцированного объекта CountVectorizer.

# Transform our text data into vector
X_train_vec = vectorizer.fit_transform(X_train).toarray()

Затем мы инстанцируем объект RandomForestClassifier с заданным случайным состоянием и подгоняем модель случайного леса, используя обучающие данные.

# Initialize random forest and train it
rf = RandomForestClassifier(random_state=2)
rf.fit(X_train_vec, y_train)

Теперь пришло время прогнозировать, используя обученную модель и преобразованные тестовые данные.

Затем мы распечатаем отчет о классификации, содержащий такие метрики оценки, как precision, recall и f1-score.

# Predict and output classification report
y_predicted = rf.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

Наконец, давайте создадим новый рисунок с заданным размером для графика матрицы путаницы и построим график матрицы путаницы.

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax

Вот весь код.

# Instantiate vectorizer class
vectorizer = CountVectorizer(min_df=1)

# Transform our text data into vector
X_train_vec = vectorizer.fit_transform(X_train).toarray()

# Initialize random forest and train it
rf = RandomForestClassifier(random_state=2)
rf.fit(X_train_vec, y_train)

# Predict and output classification report
y_predicted = rf.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Взвешенный “случайный лес”

Как видно из последней матрицы путаницы, производительность нашей модели не очень высока.

Тем не менее, этого можно было ожидать из-за работы с ограниченным количеством точек данных (5000 вместо 100000).

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

Вот код.

class_weight = compute_class_weight(class_weight= 'balanced', classes= np.unique(df_feature_critics.review_type), 
                      y = df_feature_critics.review_type.values)

class_weight_dict = dict(zip(range(len(class_weight.tolist())), class_weight.tolist()))
class_weight_dict

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Теперь мы обучим наш классификатор Random Forest на векторном текстовом входе, но на этот раз с учетом информации о весах классов, чтобы увеличить метрику оценки.

Сначала мы создадим класс CountVectorizer и, как и раньше, превратим наши текстовые данные в векторы.

Преобразуем наши текстовые данные в вектор.

vectorizer = CountVectorizer(min_df=1)
X_train_vec = vectorizer.fit_transform(X_train).toarray()

Затем мы определим случайный лес с рассчитанными весами классов и обучим его.

# Initialize random forest and train it
rf_weighted = RandomForestClassifier(random_state=2, class_weight=class_weight_dict)
rf_weighted.fit(X_train_vec, y_train)

Теперь пришло время сделать прогноз, используя тестовые данные и распечатав отчет о классификации.

# Predict and output classification report
y_predicted = rf_weighted.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

На последнем этапе мы устанавливаем размер фигуры и строим матрицу путаницы.

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf_weighted, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax)

Вот весь код.

# Instantiate vectorizer class
vectorizer = CountVectorizer(min_df=1)

# Transform our text data into vector
X_train_vec = vectorizer.fit_transform(X_train).toarray()

# Initialize random forest and train it
rf_weighted = RandomForestClassifier(random_state=2, class_weight=class_weight_dict)
rf_weighted.fit(X_train_vec, y_train)

# Predict and output classification report
y_predicted = rf_weighted.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf_weighted, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax)

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

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

Более того, поскольку вес класса 0 (“Гнилой”) больше веса класса 1 (“Свежий”), модель теперь лучше предсказывает “гнилые” отзывы о фильмах, но хуже предсказывает “свежие” отзывы о фильмах.

Это происходит потому, что модель уделяет больше внимания данным, классифицированным как “гнилые”.

Предсказание статуса фильма

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

  • Соберите все рецензии на определенный фильм.
  • Используйте нашу модель Random Forest для оценки состояния каждого отзыва (например, “свежий” или “гнилой”).
  • Чтобы классифицировать окончательный статус фильма на основе общего состояния рецензий, используйте подход, основанный на правилах, приведенных на сайте Rotten Tomatoes.

Здесь, в следующем коде, мы сначала создаем функцию predict_movie_statust, которая принимает предсказание в качестве аргумента.

Затем, в зависимости от значения positive_percentage, мы определяем статус фильма, присваивая переменной предсказания значение ‘Fresh’ или ‘Rotten’.

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

Вот код.

def predict_movie_status(prediction):
    """Assign label (Fresh/Rotten) based on prediction"""
    positive_percentage = (prediction == 1).sum()/len(prediction)*100
    
    prediction = 'Fresh' if positive_percentage >= 60 else 'Rotten'
    
    print(f'Positive review:{positive_percentage:.2f}%')
    print(f'Movie status: {prediction}')

В этом примере мы предскажем статус трех фильмов: Body of Lies, Angel Heart и The Duchess. Начнем с “Тела лжи”.

Прогноз на “Тело лжи”

Итак, как было сказано выше, сначала давайте соберем все отзывы о фильме “Тело лжи”.

Вот код

# Gather all of the reviews of Body of Lies movie
df_bol = df_merged.loc[df_merged['movie_title'] == 'Body of Lies']

df_bol.head()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

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

Вот код.

y_predicted_bol = rf_weighted.predict(vectorizer.transform(df_bol['review_content']).toarray())
predict_movie_status(y_predicted_bol)

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

И вот наш результат, давайте проверим наш результат, действителен он или нет, сравнив его со статусом ground_truth.

Вот код.

df_merged['tomatometer_status'].loc[df_merged['movie_title'] == 'Body of Lies'].unique()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Похоже, что наш прогноз оправдался, потому что статус этого фильма – Rotten, как мы и предсказывали.

Прогноз “Сердце ангела”

Здесь мы повторим все шаги.

  • Соберите все отзывы
  • Составьте прогноз
  • Сравнение

Давайте сначала соберем все рецензии на фильм Анна Каренина.

Вот код.

df_ah = df_merged.loc[df_merged['movie_title'] == 'Angel Heart']
df_ah.head()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Теперь пришло время сделать предсказание с помощью случайного леса и нашей пользовательской функции.

Вот код.

y_predicted_ah = rf_weighted.predict(vectorizer.transform(df_ah['review_content']).toarray())
predict_movie_status(y_predicted_ah)

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Давайте проведем сравнение.

Вот код.

df_merged['tomatometer_status'].loc[df_merged['movie_title'] == 'Angel Heart'].unique()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Наша модель снова предсказывает правильно.

Теперь давайте попробуем еще раз.

Предсказание “Герцогини”

Сначала давайте соберем все отзывы.

Вот код.

df_duchess = df_merged.loc[df_merged['movie_title'] == 'The Duchess']
df_duchess.head()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Теперь пришло время сделать предсказание.

Вот код.

y_predicted_duchess = rf_weighted.predict(vectorizer.transform(df_duchess['review_content']).toarray())
predict_movie_status(y_predicted_duchess)

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

Давайте сравним наше предсказание с истиной.

Вот код.

df_merged['tomatometer_status'].loc[df_merged['movie_title'] == 'The Duchess'].unique()

Вот результат.

Проект Data Science по прогнозированию рейтинга фильмов Rotten Tomatoes

А истинный рейтинг фильма – “Свежий”, что указывает на то, что прогноз нашей модели неверен.

Тем не менее, можно заметить, что прогноз нашей модели очень близок к порогу 60%, что указывает на то, что незначительное изменение модели может изменить ее прогноз с “Гнилой” на “Свежий”.

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

Предложения по улучшению работы

  1. Увеличьте объем имеющихся данных.
  2. Установите различные гиперпараметры модели случайного леса.
  3. Примените различные модели машинного обучения, чтобы найти лучшую.
  4. Настройте метод, используемый для представления текстовых данных.

Заключение

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

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

Мы также экспериментировали с выбором признаков и взвешенным классификатором случайного леса.

Во втором подходе мы использовали стандартный случайный лес и взвешенный случайный лес для прогнозирования статуса фильма для трех разных фильмов.

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

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *