{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Открытый курс по машинному обучению. Сессия № 2\n", "\n", "###
Автор материала: Липко Иван Юрьевич (slack @ivanlipko)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##
Индивидуальный проект по анализу данных
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "from matplotlib import pyplot as plt\n", "%matplotlib inline\n", "\n", "import json\n", "import seaborn as sns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 1. Описание набора данных и признаков" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**1. Описание набора данных и признаков (2 балла)**\n", " (+) Описан процесс сбора данных (если применимо), есть подробное описание решаемой задачи, в чем ее ценность, дано описание целевого и прочих признаков;\n", " (+/-) Сказано, какая задача решается, откуда данные, что есть целевой признак. Даны названия признаков;\n", " (-/+) Сказано, какая задача решается, откуда данные и что есть целевой признак;\n", " (-) Описание отсутствует и дано только название датасета или решаемой задачи, скажем, \"прогноз оттока\".\n" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Данные представляют собой **базу кинофильмов и оценок пользователей** из The Movie Database (TMDb). Данные взяты из Kaggle (https://www.kaggle.com/tmdb/tmdb-movie-metadata).\n", "\n", "Из описания известно что **данные были введены пользователями вручную**, соответственно могут быть ошибки или не соответствия с официальными источниками (All fields are filled out by users so don't expect them to agree on keywords, genres, ratings, or the like). **Метаданные были скачаны** с использованием парсера используя API TMDb's (https://gist.github.com/SohierDane/4a84cb96d220fc4791f52562be37968b). Как считается рейтинг (целевая переменная), нашёл вот что: \n", "` Популярной возможностью IMDb являются онлайн-голосования. Любой зарегистрированный посетитель сайта может голосовать за фильмы, выставляя им рейтинг: от 1 («ужасный фильм» ) до 10 («шедевр» ) баллов `\n", "\n", "Я **решаю задачу предсказания рейтинга фильма** (признак vote_average). **Ценность** заключается в следующем: можно выяснить, как зависит окупаемость фильма, его популярность, делать подбор актёров таким образом, чтобы рейтинг фильма. Хочу понять, возможно ли предсказать рейтинг фильма, зная только его краткое описание, бюджет и другие общедоступные данные.\n", "\n", "Описание признаков:\n", "\n", " - budget -- бюджет фильма (доллары)\n", " - genres -- жанр фильма\n", " - homepage -- сайт фильма\n", " - id -- номер фильма в каталоге\n", " - keywords -- ключевые слова\n", " - original_language -- оригинальный язык фильма\n", " - original_title -- оригинальное название\n", " - overview -- краткая аннотация-описание\n", " - popularity -- популярность\n", " - production_companies -- студия производства\n", " - production_countries -- страна-производитель\n", " - release_date -- дата производства (год - месяц - день)\n", " - revenue -- доход, кассовый сбор (доллары)\n", " - runtime -- продолжительность в минутах\n", " - spoken_languages -- языки фильма\n", " - status -- статус, вышел фильм или нет\n", " - tagline -- Слоган\n", " - title -- финальное название фильма\n", " - vote_average **(целевой признак)** -- средний рейтинг фильма\n", " - vote_count -- количество голосов\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def load_tmdb_movies(path):\n", " df = pd.read_csv(path)\n", " df['release_date'] = pd.to_datetime(df['release_date']).apply(lambda x: x.date())\n", " json_columns = ['genres', 'keywords', 'production_countries', 'production_companies', 'spoken_languages']\n", " for column in json_columns:\n", " df[column] = df[column].apply(json.loads)\n", " return df\n", "\n", "def load_tmdb_credits(path):\n", " df = pd.read_csv(path)\n", " json_columns = ['cast', 'crew']\n", " for column in json_columns:\n", " df[column] = df[column].apply(json.loads)\n", " return df\n", "\n", "movies = load_tmdb_movies(\"tmdb_5000_movies.csv\")\n", "credits = load_tmdb_credits(\"tmdb_5000_credits.csv\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 2. Первичный анализ признаков" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Посмотрим что у нас из себя представляют данные." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение:** Большинство признаков представляют собой json-контейнеры, которые ещё надо разворачивать и делать из них фичи." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(movies.shape)\n", "print(movies.info())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение:** Практически все важные поля имеют значения - это хорошо" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies.describe()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "p = movies.original_language.value_counts()\n", "print(p.get_values())\n", "print(movies.original_language.unique())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# распределение голосов в зависимости от языка\n", "val_en_counts = movies[movies['original_language'] == 'en']['vote_average'].value_counts().sort_index()\n", "val_ja_counts = movies[movies['original_language'] == 'ja']['vote_average'].value_counts().sort_index()\n", "val_fr_counts = movies[movies['original_language'] == 'fr']['vote_average'].value_counts().sort_index()\n", "\n", "plt.title('Распределение значений рейтинга')\n", "plt.xlabel('vote_average'), plt.ylabel('Количество')\n", "plt.plot(val_en_counts.keys(),np.log(val_en_counts.values))\n", "plt.plot(val_ja_counts.keys(),np.log(val_ja_counts.values))\n", "plt.plot(val_fr_counts.keys(),np.log(val_fr_counts.values))\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение**. Очевидно, что англоязычных фильмов больше чем других, но распределение голосов похожее." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "p = movies.vote_average.value_counts().sort_index()\n", "\n", "plt.title('Распределение значений рейтинга')\n", "plt.xlabel('vote_average')\n", "plt.ylabel('Количество')\n", "plt.plot(p.keys(),p.values)\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.scatter(x=np.log(movies.budget+1), y=np.log(movies.revenue+1), c=movies.vote_average)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# plt.scatter(x=np.log(movies.budget), y=np.log(movies.revenue), c=movies.vote_average)\n", "movies[ (movies['budget']>0) & (movies['revenue']>0) ].plot.scatter(x='budget', y='revenue', c='vote_average', figsize=(10, 10), s=45)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies[ movies['budget'] <=0].head(3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies[ movies['revenue'] <=0 ].head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение**. Несмотря на то, что пропусков данных нет, в самих данных есть проблемы. TMDB ничего не знает о бюджете и доходах некоторых фильмов. (например, The Lovers, The Tuxedo). Видимо такие фильмы придётся в дальнейшем просто убирать из обучающей выборки.\n", "\n", "Для остальных фильмов наблюдается зависимость вложения и отдачи, но однозначно сказать что дорогой фильм будет очень востребован нельзя." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movs = pd.concat([movies.budget, movies.revenue, movies.popularity, movies.vote_count, movies.vote_average], axis=1)\n", "#movs.vote_average = np.log(movs.vote_average)\n", "movs.popularity = np.log(movs.popularity+1)\n", "movs.vote_count = np.log(movs.vote_count+1)\n", "movs[ (movs.budget>0) & (movs.revenue>0)].plot.scatter(x='popularity', y='vote_average', figsize=(5, 5), c='vote_count')\n", "\n", "del movs" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**Заключение**. Сказать что популярный фильм будет иметь высоки рейтинг нельзя. Есть фильмы, которые не так популярны, но имеют высокий рейтинг." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rel_date_time = pd.to_datetime(movies.release_date)\n", "rel_date_time[ rel_date_time > '1963-01-01' ].value_counts().plot(figsize=(20, 5))\n", "del rel_date_time" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**Заключение**. TMDB в основном содержит фильмы 21 века." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Остальные признаки посмотрим, когда возьмём их из JSONa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 5. Предобработка данных " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Вытяним из JSONa все жанры, языки фильмов, страну производителя и сделаем OneHotEnconding вручную (кто знает как сделать это красивее напишите мне в Слаке)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_genres = []\n", "for i in range(0,movies.shape[0]):\n", " all_genres.append([actor['name'] for actor in movies['genres'].iloc[i][:10]])\n", "all_genres = set(x for l in all_genres for x in l) # множество содержит только уникальные элементы\n", "\n", "genres = pd.DataFrame(columns=all_genres)\n", "for i in range(0,movies.shape[0]):\n", " a = [actor['name'] for actor in movies['genres'].iloc[i][:10]]\n", " for j in all_genres:\n", " genres.at[i,j] = 0\n", " for item in a:\n", " genres.at[i,item] = 1\n", "\n", "genres.fillna(0, inplace=True)\n", "print(genres.shape)\n", "\n", "new_cols = 'genre_'+genres.columns\n", "genres.columns = new_cols\n", "# print(genres.info())\n", "# print(genres.head(5)) # для проверки\n", "# print(genres.tail(5)) # для проверки\n", "\n", "genres.to_csv('genres.csv')\n", "# genres = pd.read_csv('genres.csv')\n", "# genres = genres.drop('Unnamed: 0', axis=1)\n", "# for col in genres.columns:\n", "# genres[col] = pd.to_numeric(genres[col], errors='coerce', downcast='unsigned')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Компаний очень много и комп медленно их обрабатывает, поэтому пока не трогаю\n", "# all_prod_companies = []\n", "# for i in range(0,movies.shape[0]):\n", "# all_prod_companies.append([comp['id'] for comp in movies['production_companies'].iloc[i][:10]])\n", "# all_prod_companies = set(x for l in all_prod_companies for x in l)\n", "\n", "# prod_comps = pd.DataFrame(columns=all_prod_companies)\n", "# for i in range(0,movies.shape[0]):\n", "# a = [comp['id'] for comp in movies['production_companies'].iloc[i][:10]]\n", "# for j in all_prod_companies:\n", "# prod_comps.at[i,j] = 0\n", "# for item in a:\n", "# prod_comps.at[i,item] = 1\n", "\n", "# prod_comps.fillna(0, inplace=True)\n", "# print(prod_comps.shape)\n", "# print(prod_comps.head(3))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_prod_countrs = []\n", "for i in range(0,movies.shape[0]):\n", " all_prod_countrs.append([comp['iso_3166_1'] for comp in movies['production_countries'].iloc[i][:10]])\n", "all_prod_countrs = set(x for l in all_prod_countrs for x in l)\n", "print(all_prod_countrs)\n", "\n", "prod_countrs = pd.DataFrame(columns=all_prod_countrs)\n", "for i in range(0,movies.shape[0]):\n", " a = [countr['iso_3166_1'] for countr in movies['production_countries'].iloc[i][:10]]\n", " for j in all_prod_countrs:\n", " prod_countrs.at[i,j] = 0\n", " for item in a:\n", " prod_countrs.at[i,item] = 1\n", "\n", "prod_countrs.fillna(0, inplace=True)\n", "new_cols = 'country_'+prod_countrs.columns\n", "prod_countrs.columns = new_cols\n", "\n", "print(prod_countrs.shape)\n", "# print(prod_countrs.head(3))\n", "prod_countrs.to_csv('prod_countrs.csv')\n", "# prod_countrs = pd.read_csv('prod_countrs.csv')\n", "# prod_countrs = prod_countrs.drop('Unnamed: 0', axis=1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_spok_langs = []\n", "for i in range(0,movies.shape[0]):\n", " all_spok_langs.append([comp['iso_639_1'] for comp in movies['spoken_languages'].iloc[i][:10]])\n", "all_spok_langs = set(x for l in all_spok_langs for x in l)\n", "# print(all_spok_langs)\n", "\n", "spok_langs = pd.DataFrame(columns=all_spok_langs)\n", "for i in range(0,movies.shape[0]):\n", " a = [lang['iso_639_1'] for lang in movies['spoken_languages'].iloc[i][:10]]\n", " for j in all_spok_langs:\n", " spok_langs.at[i,j] = 0\n", " for item in a:\n", " spok_langs.at[i,item] = 1\n", "\n", "spok_langs.fillna(0, inplace=True)\n", "new_cols = 'country_'+spok_langs.columns\n", "spok_langs.columns = new_cols\n", "\n", "print(spok_langs.shape)\n", "# print(spok_langs.head(3))\n", "spok_langs.to_csv('spok_langs.csv')\n", "# prod_countrs = pd.read_csv('prod_countrs.csv')\n", "# prod_countrs = prod_countrs.drop('Unnamed: 0', axis=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "LabelEncoding оригинального языка:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import LabelEncoder\n", "\n", "labelEnc = LabelEncoder()\n", "movies.original_language = labelEnc.fit_transform(movies.original_language)\n", "# print(dict(enumerate(labelEnc.classes_)))\n", "# print(movies.original_language.head(3)) # для проверки" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Из даты релиза достаём год и месяц выпуска. Вдруг окажется что например, фильмы хорошо заходят перед новыми годом, а не перед новым учебным годом." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "temp_date_month = []\n", "temp_date = pd.to_datetime(movies.release_date)\n", "temp_date_data = [t.month for t in temp_date]\n", "movies['release_month'] = temp_date_data\n", "temp_date_data = [t.year for t in temp_date]\n", "movies['release_year'] = temp_date_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Соединяем теперь все столбцы в один DataFrame" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies = pd.concat([movies, genres, prod_countrs, spok_langs], axis=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Удаляем все не нужные признаки: страница фильма, ИД в каталоге, оригинальное название, статус." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies.drop(['homepage', 'status', 'id', 'original_title', 'title', 'release_date'], axis=1, inplace=True)\n", "movies.drop(['genres', 'production_countries', 'spoken_languages'], axis=1, inplace=True)\n", "\n", "# с чем я пока не умею работать\n", "movies.drop(['tagline', 'keywords', 'overview', 'production_companies'], axis=1, inplace=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Создаём наборы данных с признаками и целевым признаком:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies.columns[:50]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_data = movies.copy()\n", "x_data.drop('vote_average', axis=1, inplace=True)\n", "y_data = movies['vote_average']\n", "\n", "x_data.dropna(axis=0, inplace=True)\n", "y_data = y_data[x_data.index]\n", "\n", "data = pd.concat([x_data, y_data], axis=1)\n", "data.to_csv('data1.csv')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "\n", "x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.33, random_state=43)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_train_f, x_test_f, y_train_f, y_test_f = train_test_split(x_data[(x_data.budget>0) & (x_data.revenue>0)], y_data[(x_data.budget>0) & (x_data.revenue>0)], test_size=0.33, random_state=43)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 3. Первичный визуальный анализ признаков" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**3. Первичный визуальный анализ данных (4 балла)**\n", " (+) Построены визуализации (распределения признаков, матрица корреляций и т.д.), описана связь с анализом данным (п. 2). Присутствуют выводы;\n", " (+/-) Построены визуализации (распределения признаков, матрица корреляций и т.д.). Присутствуют выводы с небольшими ошибками;\n", " (-/+) Недостает важных визуализаций и/или присутствует много ошибок в выводах;\n", " (-) Отсутствует." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# TODO Рейтинг фильмов, которые меняли своё название и не меняли." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies_log = movies[(movies['budget']>0) & (movies['revenue']>0)][['vote_average', 'popularity', 'revenue', 'budget', 'vote_count','runtime']].copy()\n", "movies_log.popularity = np.log(movies_log.popularity+1)\n", "movies_log.revenue = np.log(movies_log.revenue+1)\n", "movies_log.budget = np.log(movies_log.budget+1)\n", "movies_log.vote_count = np.log(movies_log.vote_count+1)\n", "# movies_log.vote_average = np.log(movies_log.vote_average+1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sns.pairplot(data=movies_log, hue='vote_average')#, vars=['vote_average', 'popularity', 'revenue', 'budget', 'vote_count'])#,'runtime'])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(movies.release_month.value_counts())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "movies_log = movies[(movies['budget']>0) & (movies['revenue']>0)][['release_year', 'release_month', 'vote_average', 'popularity']].copy()\n", "movies_log.release_year = np.log(movies_log.release_year+1)\n", "movies_log.popularity = np.log(movies_log.popularity+1)\n", "sns.pairplot(data=movies_log, hue='release_month')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f, ax = plt.subplots(nrows=1, ncols=2, figsize=(15, 3))\n", "corr = movies[['vote_average', 'popularity', 'revenue', 'runtime', 'budget', 'vote_count', 'release_year', 'release_month']].corr()\n", "sns.heatmap(corr, cmap='YlGnBu', annot=True, ax=ax[0], fmt='.1f')\n", "\n", "corr = movies[['vote_average', 'popularity', 'revenue', 'runtime', 'budget', 'vote_count', 'release_year', 'release_month']].corr(method='spearman')\n", "sns.heatmap(corr, cmap='YlGnBu', annot=True, ax=ax[1], fmt='.1f')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "corr = movies[['vote_average','genre_Action', 'genre_Drama', 'genre_Adventure', 'genre_Crime',\n", " 'genre_Western', 'genre_Comedy', 'genre_Mystery', 'genre_Music',\n", " 'genre_History', 'genre_Documentary', 'genre_Fantasy', 'genre_Romance',\n", " 'genre_Animation', 'genre_War', 'genre_Foreign', 'genre_TV Movie',\n", " 'genre_Science Fiction', 'genre_Family', 'genre_Horror',\n", " 'genre_Thriller']].corr()\n", "f, ax = plt.subplots(figsize=(10, 10))\n", "sns.heatmap(corr, cmap='YlGnBu', annot=True, ax=ax, fmt='.1f')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение**. \n", "Что касается прогнозируемой величины: наиболее рейтинговые фильмы являются драмами. Рейтинг фильма сильно зависит от количества голосов, популярности и продолжительности.\n", "\n", "Просто наблюдения: семейный фильм скорее всего будет мультфильмом, драма скорее всего романтической и в историческом контексте, исторические фильмы чаще про войну, за популярные фильмы чаще всего голосуют. Наибольшее количество фильмов выходят в сентябре, что наверно не совсем логично. Например, в новогодние каникулы все отдыхают и обычно нечем заняться. С другой стороны это конец летнего сезона." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 4. Закономерности, \"инсайты\", особенности данных" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Здесь описание того, что было показано до этого.\n", "\n", "Заключение по приведённым выше данным вполне очевидны. Например, семейный фильм - это значит что родители пойдут с детьми на мультфильмы (жанр - анимация). Далее как наблюдение - больше всего исторических фильмов о войне, нежели о великих достижениях и гениях своего времени.\n", "\n", "Также очевидно, что люди обсуждают и голосуют за те фильмы, на которые они ходили и возможно не раз или рассказали друзьям, что можно судит по кассовым сборам.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 6. Создание новых признаков и описание этого процесса" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "scrolled": true }, "source": [ "отсутствует, жаль" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 7. Кросс-валидация, подбор параметров" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Построение пробной модели LinearRegression" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import LinearRegression#, RidgeCV, LassoCV\n", "from sklearn.metrics import mean_absolute_error, mean_squared_error" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lr = LinearRegression(n_jobs=-1)\n", "lr.fit(x_train, y_train)\n", "prediction = lr.predict(x_train)\n", "print('MAE',mean_absolute_error(y_train, prediction))\n", "print('MSE',mean_squared_error(y_train, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lr = LinearRegression(n_jobs=-1)\n", "lr.fit(x_train_f, y_train_f)\n", "prediction = lr.predict(x_train_f)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import cross_val_predict" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prediction = cross_val_predict(lr, x_train, y_train, cv=5, n_jobs=-1)\n", "print('MAE',mean_absolute_error(y_train, prediction))\n", "print('MSE',mean_squared_error(y_train, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prediction = cross_val_predict(lr, x_train_f, y_train_f, cv=5, n_jobs=-1)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**Вывод**. Если в модель не закладывать фильмы, бюджет и доход которых нулевой (здесь больше всего шумов, см. выше), то даже линейная регрессия лучше работает. Это видно по MSE, т.к. она сильнее штрафует за большие ошибки (выбросы). Кросс-валидация этот результат не улучшает." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Выбираем такое количество признаков, которые описывают 98% всех решений и посмотрим на качество прогноза." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.decomposition import PCA\n", "# из 9 домашки \n", "def plotPCA(pca, perct=90):\n", " \"\"\"\n", " График накопленного процента объясненной дисперсии по компонентам\n", " \"\"\"\n", " features = range(pca.n_components_)\n", " variance = np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100)\n", " plt.figure(figsize=(15, 7))\n", " plt.bar(features, variance)\n", " \n", " # дополнительно отметим уровень, при котором объяснены 90% дисперсии\n", " plt.hlines(y = perct, xmin=0, xmax=len(features), linestyles='dashed', colors='red')\n", " \n", " plt.xlabel('PCA components')\n", " plt.ylabel('variance')\n", " plt.xticks(features)\n", " plt.show()\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import StandardScaler\n", "\n", "scaler = StandardScaler()\n", "scaler.fit(x_train)\n", "x_train_scaled = scaler.transform(x_train)\n", "x_test_scaled = scaler.transform(x_test)\n", "prediction = cross_val_predict(lr, x_train_scaled, y_train, cv=5, n_jobs=-1)\n", "print('MAE',mean_absolute_error(y_train, prediction))\n", "print('MSE',mean_squared_error(y_train, prediction))\n", "\n", "pca = PCA()\n", "pca.fit(x_train_scaled, y_train)\n", "plotPCA(pca)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import StandardScaler\n", "\n", "scaler = StandardScaler()\n", "scaler.fit(x_train)\n", "x_train_scaled = scaler.transform(x_train_f)\n", "x_test_scaled = scaler.transform(x_test_f)\n", "prediction = cross_val_predict(lr, x_train_scaled, y_train_f, cv=5, n_jobs=-1)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))\n", "\n", "pca = PCA()\n", "pca.fit(x_train_scaled, y_train_f)\n", "plotPCA(pca)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "features = range(pca.n_components_)\n", "variance = np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100)\n", "print(variance[16*9+5], features[16*9+5])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pca = PCA(n_components=144)\n", "pca.fit(x_train_scaled, y_train_f)\n", "pca_features_train = pca.transform(x_train_scaled)\n", "pca_features_test = pca.transform(x_test_scaled)\n", "lr.fit(pca_features_train, y_train_f)\n", "prediction = lr.predict(pca_features_test)\n", "print('MAE',mean_absolute_error(y_test_f, prediction))\n", "print('MSE',mean_squared_error(y_test_f, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Уменьшение количества признаков сильно картину не улучшает, возможно это из-за масштабирования. (масштабирование коэффициентов не улучшает картину, либо я где-то ошибся, т.к. МАЕ и MSE были огромными)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Построение модели LassoCV" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import LassoCV" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "LS_CV = LassoCV(cv=5, n_jobs=-1)\n", "LS_CV.fit(x_train_f,y_train_f)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prediction = LS_CV.predict(x_train_f)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Построение модели RidgeCV" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import RidgeCV" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Rg_CV = RidgeCV(cv=5)\n", "Rg_CV.fit(x_train_f,y_train_f)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prediction = Rg_CV.predict(x_train_f)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "score_list = [0.01, 0.1, 1, 10, 100, 1000 ] #[ 'svd', 'eigen'] #['explained_variance', 'neg_mean_absolute_error', 'neg_mean_squared_error','neg_mean_squared_log_error','neg_median_absolute_error','r2']\n", "# for score in score_list:\n", "Rg_CV = RidgeCV(cv=5, alphas=score_list)\n", "Rg_CV.fit(x_train_f,y_train_f)\n", "prediction = Rg_CV.predict(x_train_f)\n", "print('MAE',mean_absolute_error(y_train_f, prediction), 'MSE',mean_squared_error(y_train_f, prediction))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Построение модели ElasticNet" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import ElasticNet\n", "from sklearn.model_selection import GridSearchCV" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "alphas = [.01, .05, .1, .2, 1.0]\n", "l1_ratios = np.linspace(.05, .15, 10)\n", "# alphas = [0.1, 1.0, 10]\n", "# l1_ratios = np.linspace(.1, .9, 3)\n", "el_net = ElasticNet()\n", "parameters = {'alpha':alphas, 'l1_ratio':l1_ratios}\n", "grid = GridSearchCV(el_net, param_grid=parameters, scoring='mean_absolute_error' ,verbose=1, cv=5, return_train_score=1, n_jobs=-1)\n", "grid.fit(x_train_f, y_train_f)\n", "print(grid.best_score_)\n", "print(grid.best_estimator_)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "el_net_best = grid.best_estimator_\n", "prediction = el_net_best.predict(x_train_f)\n", "print(el_net_best.score(x_train_f, y_train_f))\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Из рассмотренных моделей ElasticNet и RidgeCV показали хорошие результаты. Правда у ElasticNet коэффициент детерминации маловат и коэффициент `l1_ratio` такой что он по сути является RidgeCV (т.е. применятся Л2-регуляризация). Обратимся к кривым валидации для проверки. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.ensemble import RandomForestRegressor\n", "estimators = np.arange(5,60,20)\n", "min_samples_leaf = np.arange(5,20,5)\n", "parameters = {'n_estimators':estimators, 'min_samples_leaf':min_samples_leaf}\n", "rfrr = RandomForestRegressor(criterion='mae', n_jobs=-1)\n", "grid = GridSearchCV(rfrr, param_grid=parameters, scoring='mean_absolute_error', verbose=1, cv=5, return_train_score=1, n_jobs=-1)\n", "grid.fit(x_train_f, y_train_f)\n", "print(grid.best_score_)\n", "print(grid.best_estimator_)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rfrr_best = grid.best_estimator_\n", "prediction = rfrr_best.predict(x_train_f)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Лес дал неплохой результат." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.ensemble import AdaBoostRegressor\n", "\n", "estimators = np.arange(5,60,20)\n", "loss = ['linear', 'square', 'exponential']\n", "parameters = {'n_estimators':estimators, 'loss':loss}\n", "abrr = AdaBoostRegressor(random_state=42)\n", "grid = GridSearchCV(abrr, param_grid=parameters, scoring='mean_absolute_error', verbose=1, cv=5, return_train_score=1, n_jobs=-1)\n", "grid.fit(x_train_f, y_train_f)\n", "print(grid.best_score_)\n", "print(grid.best_estimator_)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "abrr_best = grid.best_estimator_\n", "prediction = abrr_best.predict(x_train_f)\n", "print('MAE',mean_absolute_error(y_train_f, prediction))\n", "print('MSE',mean_squared_error(y_train_f, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 8. Построение кривых валидации и обучения " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import learning_curve" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# from http://scikit-learn.org/stable/auto_examples/model_selection/plot_learning_curve.html#sphx-glr-auto-examples-model-selection-plot-learning-curve-py\n", "def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,\n", " n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):\n", " \"\"\"\n", " Generate a simple plot of the test and training learning curve.\n", "\n", " Parameters\n", " ----------\n", " estimator : object type that implements the \"fit\" and \"predict\" methods\n", " An object of that type which is cloned for each validation.\n", "\n", " title : string\n", " Title for the chart.\n", "\n", " X : array-like, shape (n_samples, n_features)\n", " Training vector, where n_samples is the number of samples and\n", " n_features is the number of features.\n", "\n", " y : array-like, shape (n_samples) or (n_samples, n_features), optional\n", " Target relative to X for classification or regression;\n", " None for unsupervised learning.\n", "\n", " ylim : tuple, shape (ymin, ymax), optional\n", " Defines minimum and maximum yvalues plotted.\n", "\n", " cv : int, cross-validation generator or an iterable, optional\n", " Determines the cross-validation splitting strategy.\n", " Possible inputs for cv are:\n", " - None, to use the default 3-fold cross-validation,\n", " - integer, to specify the number of folds.\n", " - An object to be used as a cross-validation generator.\n", " - An iterable yielding train/test splits.\n", "\n", " For integer/None inputs, if ``y`` is binary or multiclass,\n", " :class:`StratifiedKFold` used. If the estimator is not a classifier\n", " or if ``y`` is neither binary nor multiclass, :class:`KFold` is used.\n", "\n", " Refer :ref:`User Guide ` for the various\n", " cross-validators that can be used here.\n", "\n", " n_jobs : integer, optional\n", " Number of jobs to run in parallel (default 1).\n", " \"\"\"\n", " plt.figure()\n", " plt.title(title)\n", " if ylim is not None:\n", " plt.ylim(*ylim)\n", " plt.xlabel(\"Training examples\")\n", " plt.ylabel(\"Score\")\n", " train_sizes, train_scores, test_scores = learning_curve(\n", " estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes, scoring='mean_absolute_error')\n", " train_scores_mean = np.mean(train_scores, axis=1)\n", " train_scores_std = np.std(train_scores, axis=1)\n", " test_scores_mean = np.mean(test_scores, axis=1)\n", " test_scores_std = np.std(test_scores, axis=1)\n", " plt.grid()\n", "\n", " plt.fill_between(train_sizes, train_scores_mean - train_scores_std,\n", " train_scores_mean + train_scores_std, alpha=0.1,\n", " color=\"r\")\n", " plt.fill_between(train_sizes, test_scores_mean - test_scores_std,\n", " test_scores_mean + test_scores_std, alpha=0.1, color=\"g\")\n", " plt.plot(train_sizes, train_scores_mean, 'o-', color=\"r\",\n", " label=\"Training score\")\n", " plt.plot(train_sizes, test_scores_mean, 'o-', color=\"g\",\n", " label=\"Cross-validation score\")\n", "\n", " plt.legend(loc=\"best\")\n", " return plt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot_learning_curve(lr, 'LR learning curves', x_train, y_train, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))\n", "plot_learning_curve(lr, 'LR learning curves (filtered data)', x_train_f, y_train_f, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Судя по кривой обучения увеличение данных хорошо влияет, т.к. уменьшается вариация (varience)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot_learning_curve(LS_CV, 'LS learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Использовать эту модель не стоит, т.к. очень большое отклонение; а близкое расположение кривых при увеличении обучающей выборки говорит о высоком смещении оценки." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot_learning_curve(Rg_CV, 'Rg learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.01, 1.0, 10))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Тут выглядит очень непонятно. Вроде как не надо много данных и модель сразу же получает хорошую оценку. Масштабирование с 0,01 до 0,2 размера выборки ничего хорошего не показало. Поэтому думаю оставить эту модель ии посмотреть, что будет на тесте. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "el_net_best = grid.best_estimator_\n", "plot_learning_curve(el_net_best, 'el_net_best learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.01, .3, 5))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import cross_val_score\n", "alphas = np.linspace(0.01, 2.0, 15) #[.01, .05, .1, .2, 1.0]\n", "mse_array = []\n", "mae_array = []\n", "scores_array = []\n", "scores_std_array = []\n", "\n", "for alph in alphas:\n", " el_net_temp = ElasticNet(alpha=alph, l1_ratio=0.08333)\n", " el_net_temp.fit(x_train_f, y_train_f)\n", " \n", " scores = cross_val_score(el_net_temp, x_train_f, y_train_f, scoring='mean_absolute_error', cv=5, n_jobs=-1)\n", " prediction = el_net_temp.predict(x_train_f)\n", " \n", " scores_array.append(scores.mean())\n", " scores_std_array.append(scores.std()) \n", " mae_array.append(mean_absolute_error(y_train_f, prediction))\n", " mse_array.append(mean_squared_error(y_train_f, prediction))\n", "# print(alph, scores, 'MAE',mean_absolute_error(y_train_f, prediction), 'MSE',mean_squared_error(y_train_f, prediction))\n", "\n", "plt.figure()\n", "plt.title('Alpha - regularization')\n", "plt.xlabel(\"Alpha\")\n", "plt.ylabel(\"Score\")\n", "plt.grid()\n", "plt.fill_between(alphas, -np.asarray(scores_array) - np.asarray(scores_std_array),\n", " -np.asarray(scores_array) + np.asarray(scores_std_array), alpha=0.1,\n", " color=\"r\")\n", "plt.plot(alphas, -np.asarray(scores_array), 'o-', color=\"r\", label=\"Cross-validation score\")\n", "plt.plot(alphas, mae_array, 'o-', color=\"g\", label=\"Train score\")\n", "plt.legend(loc=\"best\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** По валидационной кривой очень похоже на высокое смещение оценки. Как интерпретировать вторую кривую (скор от регуляризации) не знаю. Думал что тоже покажет мне или смещение или разброс, но не дало." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot_learning_curve(rfrr_best, 'RandomForest learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot_learning_curve(abrr_best, 'RandomForest learning curves', x_train_f, y_train_f, ylim=None, cv=5,\n", " n_jobs=-1, train_sizes=np.linspace(.1, 1.0, 5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение.** Более привычный рисунок для проверки. Чем больше данных тем лучше, highbias. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 9. Прогноз для тестовой или отложенной выборки" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "scrolled": true }, "source": [ "### LinearRegression" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lr = LinearRegression(n_jobs=-1)\n", "lr.fit(x_train, y_train)\n", "prediction = lr.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "По отфильтрованной обучающей выборке:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lr.fit(x_train_f, y_train_f)\n", "prediction = lr.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Остальные" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "LS_CV = LassoCV(cv=5, n_jobs=-1)\n", "LS_CV.fit(x_train_f, y_train_f)\n", "prediction = LS_CV.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Rg_CV = RidgeCV(cv=5)\n", "Rg_CV.fit(x_train_f, y_train_f)\n", "prediction = Rg_CV.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "el_net_best = ElasticNet(alpha=0.01, copy_X=True, fit_intercept=True,\n", " l1_ratio=0.083333333333333329, max_iter=1000, normalize=False,\n", " positive=False, precompute=False, random_state=None,\n", " selection='cyclic', tol=0.0001, warm_start=False)\n", "el_net_best.fit(x_train_f, y_train_f)\n", "prediction = Rg_CV.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rfrr = RandomForestRegressor(bootstrap=True, criterion='mae', max_depth=None,\n", " max_features='auto', max_leaf_nodes=None,\n", " min_impurity_decrease=0.0, min_impurity_split=None,\n", " min_samples_leaf=5, min_samples_split=2,\n", " min_weight_fraction_leaf=0.0, n_estimators=45, n_jobs=-1,\n", " oob_score=False, random_state=None, verbose=0, warm_start=False)\n", "rfrr.fit(x_train_f, y_train_f)\n", "prediction = rfrr.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "abrr = AdaBoostRegressor(base_estimator=None, learning_rate=1.0, loss='linear',\n", " n_estimators=25, random_state=42)\n", "abrr.fit(x_train_f, y_train_f)\n", "prediction = abrr.predict(x_test)\n", "print('MAE',mean_absolute_error(y_test, prediction))\n", "print('MSE',mean_squared_error(y_test, prediction))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Заключение**. Оценки как отфильтрованные, так и не отфильтрованные вполне соответствуют значениям метрик на обучающей выборке. Победил Случайный лес.\n", "\n", "Я выбирал бы случайный лес или линейную регрессию. Первая как-то надёжнее, но вторая проще, разница в качестве между ними небольшая." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 10. Оценка модели с описанием выбранной метрики" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "scrolled": true }, "source": [ "Так как не понятно было изначально к чему можно было прийти я пошёл классическим путём: выбрать что-то простое (линейная регрессия) и серебрянную пулю (Случайный лес). Собственно говоря они и хорошо зашли. Если честно, то не знаю что выбрать MSE или MAE. Я думаю что MAE говорит о точности оценки, а MSE что-то вроде разброса.\n", "\n", "В целом я результатом доволен, не смотря на то, что я не использую данные об описании (можно было бы построить новые фичи, но как на это время на оставил), ключевые слова или кинокомпании. Даже без этого модели (Лес и ЛР) дают оценку с ошибкой в 100/10*0.58 = 5,8% и 6,7% соответственно. Пожалуй это и было бы основной метрикой, чем меньше процент ошибки, тем лучше - как инженерный подход." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 11. Выводы " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "scrolled": true }, "source": [ "Теперь мы можем предсказывать рейтинг фильма. Это может нам понадобится при проведении подготовительных работ над фильмом - его описание, закладывать бюджет и т.п. Почему результат такой - думаю, потому что основные признаки как популярность и количество голосов влияют больше остальных, да и фильтрация по бюджету и доходу - это было важно." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 1 }