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

Обзор набора данных

В этом проекте использовались данные из IMDB и www.the-numbers.com от https://github.com/sundeepblue/movie_rating_prediction в 2016 году, которые содержат 5043 фильма и 28 столбцов.

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

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

Как упоминалось выше, для этого проекта важны несколько столбцов, а именно «цвет», «номер_лица_в_постере» и «соотношение сторон», поэтому они были удалены.

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

(Пример: информация о кассовых сборах аватара с https://www.imdb.com/title/tt0499549/?ref_=nv_sr_srsg_0)

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

Во-первых, я разделил числовые и категориальные признаки. Зная типы данных каждой функции (см. рисунок 1), мы можем просто выбрать те, у которых тип «float64» или «int64» в качестве числового, а «object» — в качестве числового.

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

Из подсчетов выше мы видим, что некоторые числовые функции имеют большое количество пропущенных значений, таких как брутто и бюджет. У первого около 17,5% отсутствующих данных по отношению к населению, а у второго около 10%, и с обоими определенно следует обращаться осторожно и осторожно. С другой стороны, подсчет отсутствующих значений для категориальных признаков не так проблематичен. Итак, я разобрался с простыми — с категоричными сначала.

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

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

Теперь мы можем перейти к обработке отсутствующих значений числовых признаков. Помните наше наблюдение о том, что в бюджете и брутто содержится значительное количество NaN, и их следует обрабатывать с помощью TLC? Здесь я сделал предположение, что средний бюджет и валовая выручка сильно зависят от жанра, поэтому мы не можем просто заменить отсутствующий бюджет и валовую выручку средними значениями всего населения. Не имеет смысла сравнивать бюджет боевика с бюджетом романтической комедии. То же самое касается кассовых сборов боевика-блокбастера и документального фильма.

Имея в виду такое предположение, нам важно найти средний бюджет и валовую прибыль для каждого жанра. Теперь мы сталкиваемся с некоторыми дополнительными сложностями. Каждый фильм со значением «жанры» помечен как минимум одним жанром, но не ограничивается одним. Как мы рассчитываем средние значения по жанрам, когда фильмы могут неоднократно входить в разные подсчеты жанров? Поэтому я сделал второе предположение. Первый жанр, указанный для каждого фильма, должен быть самым важным жанром, который отражает суть природы этого фильма. Кто-то может возразить, что IMDB может вводить жанры в алфавитном порядке, а не по истинной последовательности важности, однако, если мы примем эту теорию, мы не сможем легко решить текущий аргумент. Предполагая, что первый жанр определенно достаточно точно описывает фильм, мы можем использовать это произвольное правило, чтобы получить приблизительное представление о среднем бюджете и валовой выручке по жанрам.

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

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

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

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

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

Исследовательский анализ данных

  • 10 самых дорогих фильмов

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

Было около 300 фильмов, которые либо не были выпущены на английском языке, либо валюта, о которой сообщалось, была не в долларах США. К сожалению, мне пришлось удалить эти фильмы, так как нет простого способа получить курс валюты к доллару США для многих уникальных стран. После этого результат, наконец, обретает смысл — просмотр некоторых фильмов о Мстителях в этом списке определенно кажется правильным!

(бюджет в миллионах долларов)

  • 10 лучших фильмов с самым высоким кассовым сбором

В этом нет ничего удивительного.

(брутто в миллионах долларов)

  • Количество фильмов, средние баллы imdb и рейтинги режимов по жанрам

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

Во-первых, как выглядит распределение количества фильмов и оценок imdb для каждого жанра? В этом запросе я сравнил размер, средние оценки imdb и оценки режима.

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

(размер жанра относительно среднего балла imdb в логарифмической шкале)

  • 10 жанров с самым высоким средним валовым доходом

(брутто в миллионах долларов)

  • 10 жанров с самым высоким средним бюджетом

(бюджет в миллионах долларов)

  • 10 фильмов с наибольшим количеством голосов

Если мы определяем популярность на imdb по наибольшему количеству голосов, вот список 10 самых популярных фильмов. Есть предположения?

(количество проголосовавших пользователей в миллионах)

  • Топ-10 фильмов с наибольшим количеством голосов по сравнению с их оценками на imdb

Неудивительно, что эта «классика» также оценивается так высоко.

  • Сколько фильмов в каждом сегменте рейтинга?

Увидев, что 10 лучших фильмов с наибольшим количеством голосов имеют такие высокие рейтинги, мне стало любопытно, сколько фильмов в этом наборе данных считаются ужасными, приличными, хорошими или потрясающими. Я определил несколько сегментов, основываясь на моем понимании рейтинга imdb, например:

  • ужасно = 0–4
  • плохо = 4,1–6
  • хорошо = 6,1–7,5
  • высокий = 7,6–8,5
  • потрясающе = 8,6–10

  • Среднее количество пользователей, проголосовавших по шкале очков

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

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

  • 10 лучших режиссеров по количеству фильмов

  • 10 лучших режиссеров по среднему баллу imdb

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

  • Средний балл для 10 лучших директоров по количеству

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

Вспоминая наши корзины оценок, мы видим, что у режиссеров с наибольшим количеством фильмов средний балл обычно находится в нормальном диапазоне, за одним исключением — Ренни Харлин попадает в плохой диапазон. Я также просмотрел полный список фильмов, снятых им, и соответствующие оценки imdb по состоянию на 2016 год, показанные в таблице ниже.

Прогнозирование рейтинга с помощью методов регрессии

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

  1. Выбор функций

Помимо нашей целевой переменной imdb_score, другие столбцы я удалил по разным причинам.

Необходимо удалить # функции

remove = ["имя_директора", "имя_актера_1", "имя_актера_2", "имя_актера_3", "жанры",

"cast_total_facebook_likes", "язык", "страна", "imdb_score", "title_year", "plot_keywords", "movie_imdb_link"]

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

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

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

Что касается content_rating и first_genre, я закодировал их с помощью Pandas get_dummies. Для удобства чтения я сбросил индекс на movie_title. На данный момент набор данных состоит из 4603 записей и 44 столбцов (полный список имен функций см. на рисунке ниже).

Затем я разделил наборы данных для поезда/проверки/тестирования. На самом деле, я разделил 80:20 только на обучение и тестирование, потому что я использовал тестовый набор на этапе перекрестной проверки и весь набор данных в качестве окончательных данных тестирования с лучшей моделью.

X1 = X.copy()

Y1 = Y.copy()

из sklearn импорт model_selection

X_train, X_test, y_train, y_test = model_selection.train_test_split(X1, Y1, test_size=0,20, shuffle=True)

print('данные для обучения имеют ‘ + str(X_train.shape[0]) + ‘ наблюдение с ‘ + str(X_train.shape[1]) + ‘ функции’)

print('тестовые данные имеют ‘ + str(X_test.shape[0]) + ‘ наблюдение с ‘ + str(X_test.shape[1]) + ‘ функции’)

обучающие данные содержат 3682 наблюдения с 44 функциями

тестовые данные содержат 921 наблюдение с 44 функциями

2. Разработка функций

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

В этом проекте я выбрал четыре модели для оценки: KNN, стохастический градиентный спуск (SGD), случайный лес и модель дерева с усилением градиента. Для KNN и SGD важно нормализовать данные, чтобы веса функций не были сильно смещены функциями в гораздо большем масштабе, чем другие. Я выбрал MinMaxScaler от sklearn.

из sklearn.preprocessing импорт MinMaxScaler

# подгонка масштабатора к обучающим данным

норма = MinMaxScaler().fit(X_train)

# преобразование обучающих данных

X_train_norm = norm.transform(X_train)

# преобразование тестовых таблиц данных

X_test_norm = norm.transform(X_test)

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

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

3. Алгоритм KNN

  • Базовая модель

из sklearn.metrics импорт mean_squared_error

из sklearn.neighbors импорт KNeighborsRegressor

model = KNeighborsRegressor(n_neighbors=5, metric = ‘евклидово’)

печать(модель)

model.fit(X_train,y_train)

KNeighborsRegressor(algorithm='auto', leaf_size=30, metric='euclidean',

metric_params=None, n_jobs=None, n_neighbors=5, p=2,

weights=’uniform’)

pred_y = model.predict(X_test)

score=model.score(X_test,y_test)

печать(оценка)

mse = mean_squared_error(y_test, pred_y)

print("Среднеквадратичная ошибка:", mse)

0.2090375513095487

Среднеквадратическая ошибка: 1,0746440825190011

  • Резюме поиска по сетке

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

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

из sklearn.model_selection импорт GridSearchCV

# вспомогательная функция для распечатки результатов поиска в сетке

def print_grid_search_metrics(gs):

print («Лучший результат: « + str(gs.best_score_))

print («Лучший набор параметров:»)

best_parameters = gs.best_params_

for param_name in sorted(best_parameters.keys()):

print(имя_параметра + ‘:’ + str(best_parameters[имя_параметра]))

# гипернастройка K

параметры = {

'n_neighbors':[1,3,5,7,9]

}

Grid_KNN = GridSearchCV(KNeighborsRegressor(metric = ‘euclidean’),parameters, cv=5, refit = True)

Grid_KNN.fit(X_train, y_train)

print_grid_search_metrics(Grid_KNN)

Лучший результат: 0,19808765952194243

Оптимальный набор параметров:

N_соседей:9

# сохранить лучшую модель Knn из gridsearch

best_KNN_model = Grid_KNN.best_estimator_

  • Проверка на тестовом наборе

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

best_KNN_model.fit(X_test, y_test)

KNeighborsRegressor(algorithm='auto', leaf_size=30, metric='euclidean',

metric_params=None, n_jobs=None, n_neighbors=9, p=2,

weights=’uniform’)

pred_y_test = best_KNN_model.predict(X_test)

score=best_KNN_model.score(X_test,y_test)

печать(оценка)

mse = mean_squared_error(y_test, pred_y_test)

print("Среднеквадратичная ошибка:", mse)

0.37079140158368207

Среднеквадратическая ошибка: 0,8548766102331068

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

  • Оценка производительности модели на всем наборе данных

best_KNN_model.fit(X1, Y1)

pred_y_all = best_KNN_model.predict(X1)

score=best_KNN_model.score(X1, Y1)

печать(оценка)

mse = mean_squared_error(Y1, pred_y_all)

print("Среднеквадратичная ошибка:", mse)

0.3786777408024073

Среднеквадратическая ошибка: 0,767583111390049

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

4. Стохастический регрессор градиентного спуска

  • Базовая модель

из sklearn.linear_model импорт SGDRegressor

clf = SGDRegressor(max_iter=1000, tol=1e-3, random_state= 42)

clf.fit(X_train, y_train)

y_pred_sgd = clf.predict(X_test)

Среднеквадратическая ошибка:

5.350491667481222e+38

По базовой модели я знал, что это ужасная модель по сравнению с KNN. Но я хотел посмотреть, насколько CV поиска по сетке может улучшить MSE, тем более что скорость обучения по умолчанию (0,0001) может быть слишком низкой для хорошей сходимости модели.

  • Резюме поиска по сетке

param_grid = {

альфа: [0,0001 , 0,001 , 0,01 , 0,1 , 1 , 10 , 100],

'learning_rate': ['постоянный', 'оптимальный', 'invscaling'],

'max_iter': [1000, 2000, 3000]

}

GRID_SGD = GridSearchCV(clf, param_grid, refit = True)

GRID_SGD.fit(X_train, y_train)

Лучший результат: -2,785298996915254e+30

Оптимальный набор параметров:

альфа:100

learning_rate: оптимальный

max_iter:1000

Ужас, опять же. Я продолжал проверять и оценивать производительность в блокноте Python, но в этом отчете я опущу подробности, так как мы уже можем сказать, что это, возможно, худший вариант. Вероятно, это связано с тем, что Stochastic Gradient Descent Rregressor по-прежнему является линейной регрессией, а с количеством функций и характером наших функций линейная зависимость просто нереалистична.

5. Случайный регрессор леса

  • Базовая модель

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

из sklearn.ensemble импорт RandomForestRegressor

RF_regressor = RandomForestRegressor(random_state = 42)

RF_regressor.fit(X1_train, y1_train)

RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, критерий=’mse’,

max_depth=Нет, max_features=’auto’, max_leaf_nodes=Нет,

max_samples=Нет, min_impurity_decrease=0,0,

min_impurity_split=Нет, min_samples_leaf=1,

min_samples_split=2, min_weight_fraction_leaf=0,0,

n_estimators=100, n_jobs=нет, oob_score=ложь,

random_state=42, verbose=0, warm_start=False)

base_RF_pred_y = RF_regressor.predict(X1_test)

score=RF_regressor.score(X1_test,y1_test)

печать(оценка)

mse = mean_squared_error(y1_test, base_RF_pred_y)

print("Среднеквадратичная ошибка:", mse)

0.5198268043465617

Среднеквадратическая ошибка: 0,5731125939196527

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

  • Резюме поиска по сетке

параметры = {

n_estimators: [60, 80, 100, 120, 140],

'max_features': ["auto", "sqrt", "log2"]

}

Grid_RF = GridSearchCV(RF_regressor, параметры, cv=5, refit = True)

Grid_RF.fit(X1_train, y1_train)

Лучший результат: 0,5134058647370467

Оптимальный набор параметров:

max_features:авто

n_estimators:140

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

best_RF_model = Grid_RF.best_estimator_

  • Проверка на тестовом наборе

best_RF_model.fit(X1_test, y1_test)

RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, критерий=’mse’,

max_depth=Нет, max_features=’auto’, max_leaf_nodes=Нет,

max_samples=Нет, min_impurity_decrease=0,0,

min_impurity_split=Нет, min_samples_leaf=1,

min_samples_split=2, min_weight_fraction_leaf=0,0,

n_estimators=140, n_jobs=нет, oob_score=ложь,

random_state=42, verbose=0, warm_start=False)

pred_y_test_rf = best_RF_model.predict(X1_test)

score=best_RF_model.score(X1_test,y1_test)

печать(оценка)

mse = mean_squared_error(y1_test, pred_y_test_rf)

print("Среднеквадратичная ошибка:", mse)

0.9220988427331143

Среднеквадратическая ошибка: 0,09297923064991469

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

  • Оценка производительности модели на всем наборе данных

best_RF_model.fit(X2,Y2)

pred_y_rf_all = best_RF_model.predict(X2)

score=best_RF_model.score(X2,Y2)

печать(оценка)

mse = mean_squared_error(Y2, pred_y_rf_all)

print("Среднеквадратичная ошибка:", mse)

0.9354247043691606

Среднеквадратическая ошибка: 0,0797764857213796

Примечание: в приведенном выше коде X2 и Y2 являются глубокими копиями исходных данных X и Y. Мы видим, что Random Forest — безусловно лучший алгоритм. Поскольку классический древовидный алгоритм значительно улучшил MSE, я хотел попробовать другой древовидный алгоритм, особенно ансамблевый, чтобы посмотреть, можно ли еще улучшить MSE, и я выбрал регрессор Gradient Boosting Tree.

6. Регрессор дерева повышения градиента

  • Базовая модель

из sklearn.ensemble импорт GradientBoostingRegressor

base_GBR = GradientBoostingRegressor(random_state=42)

base_GBR.fit(X1_train, y1_train)

base_GBR_pred_y = base_GBR.predict(X1_test)

score=base_GBR.score(X1_test,y1_test)

печать(оценка)

mse = mean_squared_error(y1_test, base_GBR_pred_y)

print("Среднеквадратичная ошибка:", mse)

0.49666344765894305

Среднеквадратическая ошибка: 0,6007593088035642

MSE на базовой модели GBT не так хорош, как Random Forest, но ненамного хуже.

  • Резюме поиска по сетке

параметры = {

'learning_rate': [0,05, 0,1, 0,25, 0,5],

n_estimators: [60, 80, 100, 120, 140],

'max_features': ["auto", "sqrt", "log2"]

}

Grid_GBR = GridSearchCV(base_GBR, параметры, cv=5, refit = True)

Grid_GBR.fit(X1_train, y1_train)

Лучший результат: 0,5251711024075416

Оптимальный набор параметров:

learning_rate:0,25

max_features:авто

n_estimators:140

best_GBR_model = Grid_GBR.best_estimator_

  • Проверка на тестовом наборе

best_GBR_model.fit(X1_test, y1_test)

GradientBoostingRegressor(alpha=0,9, ccp_alpha=0,0, критерий=’friedman_mse’,

init=None, learning_rate=0,25, loss=’ls’, max_depth=3,

max_features=’auto’, max_leaf_nodes=Нет,

min_impurity_decrease=0,0, min_impurity_split=нет,

min_samples_leaf=1, min_samples_split=2,

min_weight_fraction_leaf=0,0, n_estimators=140,

n_iter_no_change=Нет, presort=’deprecated’,

random_state=42, subsample=1,0, tol=0,0001,

validation_fraction=0.1, verbose=0, warm_start=False)

pred_y_test_gbr = best_GBR_model.predict(X1_test)

score=best_GBR_model.score(X1_test,y1_test)

печать(оценка)

mse = mean_squared_error(y1_test, pred_y_test_gbr)

print("Среднеквадратичная ошибка:", mse)

0.9247441691323127

Среднеквадратическая ошибка: 0,0898218909896998

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

  • Оценка производительности модели на всем наборе данных

best_GBR_model.fit(X2,Y2)

pred_y__gbr_all = best_GBR_model.predict(X2)

score=best_GBR_model.score(X2,Y2)

печать(оценка)

mse = mean_squared_error(Y2, pred_y__gbr_all)

print("Среднеквадратичная ошибка:", mse)

0.7506000450775129

Среднеквадратическая ошибка: 0,3081093434945819

7. Лучшая модель и важность функции

Производительность нашего алгоритма, ранжированная по MSE, выглядит следующим образом: Случайный лес › Дерево повышения градиента › KNN › SGD. Random Forest и Gradient Boosting Tree имели схожую производительность, в то время как KNN дальше от древовидных алгоритмов. SGD доказал, что линейная регрессия далека от идеала для изначально нелинейной задачи. Таким образом, последним шагом в нашем прогнозе является вычисление важности признаков на основе лучшей модели и ранжирование параметров.

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

  • Важность встроенной радиочастотной функции

из sklearn.inspection импорт permutation_importance

из matplotlib импортировать pyplot как plt

sorted_idx = best_RF_model.feature_importances_.argsort()

plt.barh(X2.columns, best_RF_model.feature_importances_[sorted_idx])

plt.xlabel("Важность функции случайного леса")

  • Важность на основе перестановки

Этот метод будет случайным образом перемешивать каждую функцию и вычислять изменение производительности модели. Функции, которые больше всего влияют на производительность, являются наиболее важными. — хорошее объяснение из этой статьи: https://mljar.com/blog/feature-importance-in-random-forest/

perm_importance = permutation_importance(best_RF_model, X2, Y2)

sorted_idx = perm_importance.importances_mean.argsort()

plt.barh(X2.columns, best_RF_model.feature_importances_[sorted_idx])

plt.xlabel("Важность функции случайного леса")

Результаты двух способов вычисления согласуются. Поскольку функции с самым высоким рейтингом являются фиктивными переменными, в интерпретации мы можем сказать, что жанр и рейтинг контента очень важны для прогнозирования оценок imdb. Если мы посмотрим на остальные функции, помимо рейтинга жанра и контента, то год, movie_facebook_likes, Actor_2_facebook_likes, бюджет и num_users_for Review — это 5 самых важных функций в нашей лучшей модели.

Это конец этого проекта! Спасибо, что дочитали до этого места, если да, и не стесняйтесь обсуждать любые вопросы, связанные со мной, через LinkedIn! Полный код проекта можно найти в моем репозитории: https://github.com/jingkunzler211/IMDB_prediction.

До следующего раза, счастливого машинного обучения, адиос!