\n",
"\n",
"## Специализация \"Машинное обучение и анализ данных\"\n",
"
Автор материала: программист-исследователь Mail.Ru Group, старший преподаватель Факультета Компьютерных Наук ВШЭ [Юрий Кашницкий](https://yorko.github.io/)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#
Capstone проект №1 Идентификация пользователей по посещенным веб-страницам\n",
"\n",
"\n",
"#
Неделя 4. Сравнение алгоритмов классификации\n",
"\n",
"Теперь мы наконец подойдем к обучению моделей классификации, сравним на кросс-валидации несколько алгоритмов, разберемся, какие параметры длины сессии (*session_length* и *window_size*) лучше использовать. Также для выбранного алгоритма построим кривые валидации (как качество классификации зависит от одного из гиперпараметров алгоритма) и кривые обучения (как качество классификации зависит от объема выборки).\n",
"\n",
"**План 4 недели:**\n",
"- Часть 1. Сравнение нескольких алгоритмов на сессиях из 10 сайтов\n",
"- Часть 2. Выбор параметров – длины сессии и ширины окна\n",
"- Часть 3. Идентификация конкретного пользователя и кривые обучения\n",
" \n",
"\n",
"\n",
"**В этой части проекта Вам могут быть полезны видеозаписи следующих лекций курса \"Обучение на размеченных данных\":**\n",
" - [Линейная классификация](https://www.coursera.org/learn/supervised-learning/lecture/jqLcO/linieinaia-klassifikatsiia)\n",
" - [Сравнение алгоритмов и выбор гиперпараметров](https://www.coursera.org/learn/supervised-learning/lecture/aF79U/sravnieniie-alghoritmov-i-vybor-ghipierparamietrov)\n",
" - [Кросс-валидация. Sklearn.cross_validation](https://www.coursera.org/learn/supervised-learning/lecture/XbHEk/kross-validatsiia-sklearn-cross-validation)\n",
" - [Линейные модели. Sklearn.linear_model. Классификация](https://www.coursera.org/learn/supervised-learning/lecture/EBg9t/linieinyie-modieli-sklearn-linear-model-klassifikatsiia)\n",
" - и многие другие\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Задание\n",
"1. Заполните код в этой тетрадке \n",
"2. Если вы проходите специализацию Яндеса и МФТИ, пошлите файл с ответами в соответствующем Programming Assignment. Если вы проходите курс ODS, выберите ответы в [веб-форме](https://docs.google.com/forms/d/12VB7kmzDoSVzSpQNaJp0tR-2t8K8PynQopP3dypf7i4). "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# pip install watermark\n",
"%load_ext watermark"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%watermark -v -m -p numpy,scipy,pandas,matplotlib,statsmodels,sklearn -g"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from __future__ import division, print_function\n",
"# отключим всякие предупреждения Anaconda\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"from time import time\n",
"import itertools\n",
"import os\n",
"import numpy as np\n",
"import pandas as pd\n",
"import seaborn as sns\n",
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"import pickle\n",
"from scipy.sparse import csr_matrix\n",
"from sklearn.model_selection import train_test_split, cross_val_score, StratifiedKFold, GridSearchCV\n",
"from sklearn.metrics import accuracy_score, f1_score"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Поменяйте на свой путь к данным\n",
"PATH_TO_DATA = 'capstone_user_identification'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Часть 1. Сравнение нескольких алгоритмов на сессиях из 10 сайтов"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Загрузим сериализованные ранее объекты *X_sparse_10users* и *y_10users*, соответствующие обучающей выборке для 10 пользователей.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open(os.path.join(PATH_TO_DATA, \n",
" 'X_sparse_10users.pkl'), 'rb') as X_sparse_10users_pkl:\n",
" X_sparse_10users = pickle.load(X_sparse_10users_pkl)\n",
"with open(os.path.join(PATH_TO_DATA, \n",
" 'y_10users.pkl'), 'rb') as y_10users_pkl:\n",
" y_10users = pickle.load(y_10users_pkl)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Здесь более 14 тысяч сессий и почти 5 тысяч уникальных посещенных сайтов.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"X_sparse_10users.shape"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Разобьем выборку на 2 части. На одной будем проводить кросс-валидацию, на второй – оценивать модель, обученную после кросс-валидации.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"X_train, X_valid, y_train, y_valid = train_test_split(X_sparse_10users, y_10users, \n",
" test_size=0.3, \n",
" random_state=17, stratify=y_10users)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Зададим заранее тип кросс-валидации: 3-кратная, с перемешиванием, параметр random_state=17 – для воспроизводимости.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=17)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вспомогательная функция для отрисовки кривых валидации после запуска GridSearchCV (или RandomizedCV).**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def plot_validation_curves(param_values, grid_cv_results_):\n",
" train_mu, train_std = grid_cv_results_['mean_train_score'], grid_cv_results_['std_train_score']\n",
" valid_mu, valid_std = grid_cv_results_['mean_test_score'], grid_cv_results_['std_test_score']\n",
" train_line = plt.plot(param_values, train_mu, '-', label='train', color='green')\n",
" valid_line = plt.plot(param_values, valid_mu, '-', label='test', color='red')\n",
" plt.fill_between(param_values, train_mu - train_std, train_mu + train_std, edgecolor='none',\n",
" facecolor=train_line[0].get_color(), alpha=0.2)\n",
" plt.fill_between(param_values, valid_mu - valid_std, valid_mu + valid_std, edgecolor='none',\n",
" facecolor=valid_line[0].get_color(), alpha=0.2)\n",
" plt.legend()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**1. Обучите `KNeighborsClassifier` со 100 ближайшими соседями (остальные параметры оставьте по умолчанию, только `n_jobs`=-1 для распараллеливания) и посмотрите на долю правильных ответов на 3-кратной кросс-валидации (ради воспроизводимости используйте для этого объект `StratifiedKFold` `skf`) по выборке `(X_train, y_train)` и отдельно на выборке `(X_valid, y_valid)`.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.neighbors import KNeighborsClassifier"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"knn = KNeighborsClassifier ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 1. Посчитайте доли правильных ответов для KNeighborsClassifier на кросс-валидации и отложенной выборке. Округлите каждое до 3 знаков после запятой и введите через пробел.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**2. Обучите случайный лес (`RandomForestClassifier`) из 100 деревьев (для воспроизводимости `random_state`=17). Посмотрите на OOB-оценку (для этого надо сразу установить `oob_score`=True) и на долю правильных ответов на выборке `(X_valid, y_valid)`. Для распараллеливания задайте `n_jobs`=-1.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.ensemble import RandomForestClassifier"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"forest = RandomForestClassifier ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 2. Посчитайте доли правильных ответов для `RandomForestClassifier` при Out-of-Bag оценке и на отложенной выборке. Округлите каждое до 3 знаков после запятой и введите через пробел.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"write_answer_to_file(''' ВАШ КОД ЗДЕСЬ ''',\n",
" 'answer4_2.txt')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!cat answer4_2.txt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**3. Обучите логистическую регрессию (`LogisticRegression`) с параметром `C` по умолчанию и `random_state`=17 (для воспроизводимости). Посмотрите на долю правильных ответов на кросс-валидации (используйте объект `skf`, созданный ранее) и на выборке `(X_valid, y_valid)`. Для распараллеливания задайте `n_jobs=-1`.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.linear_model import LogisticRegression, LogisticRegressionCV"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"logit = LogisticRegression ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Почитайте документацию к [LogisticRegressionCV](http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegressionCV.html). Логистическая регрессия хорошо изучена, и для нее существуют алгоритмы быстрого подбора параметра регуляризации `C` (быстрее, чем с `GridSearchCV`).**\n",
"\n",
"**С помощью `LogisticRegressionCV` подберите параметр `C` для `LogisticRegression` сначала в широком диапазоне: 10 значений от 1e-4 до 1e2, используйте `logspace` из `NumPy`. Укажите у `LogisticRegressionCV` параметры `multi_class`='multinomial' и `random_state`=17. Для кросс-валидации используйте объект `skf`, созданный ранее. Для распараллеливания задайте `n_jobs=-1`.**\n",
"\n",
"**Нарисуйте кривые валидации по параметру `C`.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"logit_c_values1 = np.logspace(-4, 2, 10)\n",
"\n",
"logit_grid_searcher1 = LogisticRegressionCV ''' ВАШ КОД ЗДЕСЬ ''' \n",
"logit_grid_searcher1.fit(X_train, y_train)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Средние значения доли правильных ответов на кросс-валидации по каждому из 10 параметров `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"logit_mean_cv_scores1 = ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выведите лучшее значение доли правильных ответов на кросс-валидации и соответствующее значение `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Нарисуйте график зависимости доли правильных ответов на кросс-валидации от `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(logit_c_values1, logit_mean_cv_scores1);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Теперь то же самое, только значения параметра `C` перебирайте в диапазоне `np.linspace`(0.1, 7, 20). Опять нарисуйте кривые валидации, определите максимальное значение доли правильных ответов на кросс-валидации.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"logit_c_values2 = np.linspace(0.1, 7, 20)\n",
"\n",
"logit_grid_searcher2 = LogisticRegressionCV ''' ВАШ КОД ЗДЕСЬ '''\n",
"logit_grid_searcher2.fit(X_train, y_train)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Средние значения доли правильных ответов на кросс-валидации по каждому из 10 параметров `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выведите лучшее значение доли правильных ответов на кросс-валидации и соответствующее значение `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Нарисуйте график зависимости доли правильных ответов на кросс-валидации от `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.plot(logit_c_values2, logit_mean_cv_scores2);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выведите долю правильных ответов на выборке `(X_valid, y_valid)` для логистической регрессии с лучшим найденным значением `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"logit_cv_acc = accuracy_score ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 3. Посчитайте доли правильных ответов для `logit_grid_searcher2` на кросс-валидации для лучшего значения параметра `C` и на отложенной выборке. Округлите каждое до 3 знаков после запятой и выведите через пробел.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**4. Обучите линейный SVM (`LinearSVC`) с параметром `C`=1 и `random_state`=17 (для воспроизводимости). Посмотрите на долю правильных ответов на кросс-валидации (используйте объект `skf`, созданный ранее) и на выборке `(X_valid, y_valid)`.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.svm import LinearSVC"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"svm = LinearSVC ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**С помощью `GridSearchCV` подберите параметр `C` для SVM сначала в широком диапазоне: 10 значений от 1e-4 до 1e4, используйте `linspace` из NumPy. Нарисуйте кривые валидации.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"svm_params1 = {'C': np.linspace(1e-4, 1e4, 10)}\n",
"\n",
"svm_grid_searcher1 = GridSearchCV ''' ВАШ КОД ЗДЕСЬ '''\n",
"svm_grid_searcher1.fit(X_train, y_train)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выведите лучшее значение доли правильных ответов на кросс-валидации и соответствующее значение `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Нарисуйте график зависимости доли правильных ответов на кросс-валидации от `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_validation_curves(svm_params1['C'], svm_grid_searcher1.cv_results_)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Но мы помним, что с параметром регуляризации по умолчанию (С=1) на кросс-валидации доля правильных ответов выше. Это тот случай (не редкий), когда можно ошибиться и перебирать параметры не в том диапазоне (причина в том, что мы взяли равномерную сетку на большом интервале и упустили действительно хороший интервал значений `C`). Здесь намного осмысленней подбирать `C` в районе 1, к тому же, так модель быстрее обучается, чем при больших `C`. **\n",
"\n",
"**С помощью `GridSearchCV` подберите параметр `C` для SVM в диапазоне (1e-3, 1), 30 значений, используйте `linspace` из NumPy. Нарисуйте кривые валидации.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"svm_params2 = {'C': np.linspace(1e-3, 1, 30)}\n",
"\n",
"svm_grid_searcher2 = GridSearchCV ''' ВАШ КОД ЗДЕСЬ '''\n",
"svm_grid_searcher2.fit(X_train, y_train)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выведите лучшее значение доли правильных ответов на кросс-валидации и соответствующее значение `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Нарисуйте график зависимости доли правильных ответов на кросс-валидации от С."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_validation_curves(svm_params2['C'], svm_grid_searcher2.cv_results_)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Выведите долю правильных ответов на выборке `(X_valid, y_valid)` для `LinearSVC` с лучшим найденным значением `C`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"svm_cv_acc = accuracy_score ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 4. Посчитайте доли правильных ответов для `svm_grid_searcher2` на кросс-валидации для лучшего значения параметра `C` и на отложенной выборке. Округлите каждое до 3 знаков после запятой и выведите через пробел.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Часть 2. Выбор параметров – длины сессии и ширины окна"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Возьмем `LinearSVC`, показавший лучшее качество на кросс-валидации в 1 части, и проверим его работу еще на 8 выборках для 10 пользователей (с разными сочетаниями параметров *session_length* и *window_size*). Поскольку тут уже вычислений побольше, мы не будем каждый раз заново подбирать параметр регуляризации `C`.**\n",
"\n",
"**Определите функцию `model_assessment`, ее документация описана ниже. Обратите внимание на все детали. Например, на то, что разбиение выборки с `train_test_split` должно быть стратифицированным. Не теряйте нигде `random_state`.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def model_assessment(estimator, path_to_X_pickle, path_to_y_pickle, cv, random_state=17, test_size=0.3):\n",
" '''\n",
" Estimates CV-accuracy for (1 - test_size) share of (X_sparse, y) \n",
" loaded from path_to_X_pickle and path_to_y_pickle and holdout accuracy for (test_size) share of (X_sparse, y).\n",
" The split is made with stratified train_test_split with params random_state and test_size.\n",
" \n",
" :param estimator – Scikit-learn estimator (classifier or regressor)\n",
" :param path_to_X_pickle – path to pickled sparse X (instances and their features)\n",
" :param path_to_y_pickle – path to pickled y (responses)\n",
" :param cv – cross-validation as in cross_val_score (use StratifiedKFold here)\n",
" :param random_state – for train_test_split\n",
" :param test_size – for train_test_split\n",
" \n",
" :returns mean CV-accuracy for (X_train, y_train) and accuracy for (X_valid, y_valid) where (X_train, y_train)\n",
" and (X_valid, y_valid) are (1 - test_size) and (testsize) shares of (X_sparse, y).\n",
" '''\n",
" \n",
" ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Убедитесь, что функция работает.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"model_assessment(svm_grid_searcher2.best_estimator_, \n",
" os.path.join(PATH_TO_DATA, 'X_sparse_10users.pkl'),\n",
" os.path.join(PATH_TO_DATA, 'y_10users.pkl'), skf, random_state=17, test_size=0.3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Примените функцию *model_assessment* для лучшего алгоритма из предыдущей части (а именно, `svm_grid_searcher2.best_estimator_`) и 9 выборок вида с разными сочетаниями параметров *session_length* и *window_size* для 10 пользователей. Выведите в цикле параметры *session_length* и *window_size*, а также результат вывода функции *model_assessment*. \n",
"Удобно сделать так, чтоб *model_assessment* возвращала 3-им элементом время, за которое она выполнилась. На моем ноуте этот участок кода выполнился за 20 секунд. Но со 150 пользователями каждая итерация занимает уже несколько минут.**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Здесь для удобства стоит создать копии ранее созданных pickle-файлов X_sparse_10users.pkl, X_sparse_150users.pkl, y_10users.pkl и y_150users.pkl, добавив к их названиям s10_w10, что означает длину сессии 10 и ширину окна 10. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!cp $PATH_TO_DATA/X_sparse_10users.pkl $PATH_TO_DATA/X_sparse_10users_s10_w10.pkl \n",
"!cp $PATH_TO_DATA/X_sparse_150users.pkl $PATH_TO_DATA/X_sparse_150users_s10_w10.pkl \n",
"!cp $PATH_TO_DATA/y_10users.pkl $PATH_TO_DATA/y_10users_s10_w10.pkl \n",
"!cp $PATH_TO_DATA/y_150users.pkl $PATH_TO_DATA/y_150users_s10_w10.pkl "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"estimator = svm_grid_searcher2.best_estimator_\n",
"\n",
"for window_size, session_length in itertools.product([10, 7, 5], [15, 10, 7, 5]):\n",
" if window_size <= session_length:\n",
" path_to_X_pkl = ''' ВАШ КОД ЗДЕСЬ '''\n",
" path_to_y_pkl = ''' ВАШ КОД ЗДЕСЬ '''\n",
" print ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 5. Посчитайте доли правильных ответов для `LinearSVC` с настроенным параметром `C` и выборки `X_sparse_10users_s15_w5`. Укажите доли правильных ответов на кросс-валидации и на отложенной выборке. Округлите каждое до 3 знаков после запятой и выведите через пробел.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Прокомментируйте полученные результаты. Сравните для 150 пользователей доли правильных ответов на кросс-валидации и оставленной выборке для сочетаний параметров (*session_length, window_size*): (5,5), (7,7) и (10,10). На среднем ноуте это может занять до часа – запаситесь терпением, это Data Science :) **\n",
"\n",
"**Сделайте вывод о том, как качество классификации зависит от длины сессии и ширины окна.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"estimator = svm_grid_searcher2.best_estimator_\n",
"\n",
"for window_size, session_length in [(5,5), (7,7), (10,10)]:\n",
" path_to_X_pkl = ''' ВАШ КОД ЗДЕСЬ '''\n",
" path_to_y_pkl = ''' ВАШ КОД ЗДЕСЬ '''\n",
" print ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 6. Посчитайте доли правильных ответов для `LinearSVC` с настроенным параметром `C` и выборки `X_sparse_150users`. Укажите доли правильных ответов на кросс-валидации и на отложенной выборке. Округлите каждое до 3 знаков после запятой и выведите через пробел.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Часть 3. Идентификация конкретного пользователя и кривые обучения"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Поскольку может разочаровать, что многоклассовая доля правильных ответов на выборке из 150 пользовалей невелика, порадуемся тому, что конкретного пользователя можно идентифицировать достаточно хорошо. **"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Загрузим сериализованные ранее объекты *X_sparse_150users* и *y_150users*, соответствующие обучающей выборке для 150 пользователей с параметрами (*session_length, window_size*) = (10,10). Так же точно разобьем их на 70% и 30%.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open(os.path.join(PATH_TO_DATA, 'X_sparse_150users.pkl'), 'rb') as X_sparse_150users_pkl:\n",
" X_sparse_150users = pickle.load(X_sparse_150users_pkl)\n",
"with open(os.path.join(PATH_TO_DATA, 'y_150users.pkl'), 'rb') as y_150users_pkl:\n",
" y_150users = pickle.load(y_150users_pkl)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"X_train_150, X_valid_150, y_train_150, y_valid_150 = train_test_split(X_sparse_150users, \n",
" y_150users, test_size=0.3, \n",
" random_state=17, stratify=y_150users)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Обучите `LogisticRegressionCV` для одного значения параметра `C` (лучшего на кросс-валидации в 1 части, используйте точное значение, не на глаз). Теперь будем решать 150 задач \"Один-против-Всех\", поэтому укажите аргумент `multi_class`='ovr'. Как всегда, где возможно, указывайте `n_jobs=-1` и `random_state`=17.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"logit_cv_150users = LogisticRegressionCV ''' ВАШ КОД ЗДЕСЬ '''\n",
"logit_cv_150users.fit(X_train_150, y_train_150)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Посмотрите на средние доли правильных ответов на кросс-валидации в задаче идентификации каждого пользователя по отдельности.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"cv_scores_by_user = {}\n",
"for user_id in logit_cv_150users.scores_:\n",
" print('User {}, CV score: {}'.format ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Результаты кажутся впечатляющими, но возможно, мы забываем про дисбаланс классов, и высокую долю правильных ответов можно получить константным прогнозом. Посчитайте для каждого пользователя разницу между долей правильных ответов на кросс-валидации (только что посчитанную с помощью `LogisticRegressionCV`) и долей меток в *y_train_150*, отличных от ID \n",
" этого пользователя (именно такую долю правильных ответов можно получить, если классификатор всегда \"говорит\", что это не пользователь с номером $i$ в задаче классификации $i$-vs-All).**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class_distr = np.bincount(y_train_150.astype('int'))\n",
"\n",
"for user_id in np.unique(y_train_150):\n",
" ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"num_better_than_default = (np.array(list(acc_diff_vs_constant.values())) > 0).sum()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Вопрос 7. Посчитайте долю пользователей, для которых логистическая регрессия на кросс-валидации дает прогноз лучше константного. Округлите до 3 знаков после запятой.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Дальше будем строить кривые обучения для конкретного пользователя, допустим, для 128-го. Составьте новый бинарный вектор на основе *y_150users*, его значения будут 1 или 0 в зависимости от того, равен ли ID-шник пользователя 128.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"y_binary_128 = ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from sklearn.model_selection import learning_curve\n",
"\n",
"def plot_learning_curve(val_train, val_test, train_sizes, \n",
" xlabel='Training Set Size', ylabel='score'):\n",
" def plot_with_err(x, data, **kwargs):\n",
" mu, std = data.mean(1), data.std(1)\n",
" lines = plt.plot(x, mu, '-', **kwargs)\n",
" plt.fill_between(x, mu - std, mu + std, edgecolor='none',\n",
" facecolor=lines[0].get_color(), alpha=0.2)\n",
" plot_with_err(train_sizes, val_train, label='train')\n",
" plot_with_err(train_sizes, val_test, label='valid')\n",
" plt.xlabel(xlabel); plt.ylabel(ylabel)\n",
" plt.legend(loc='lower right');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Посчитайте доли правильных ответов на кросс-валидации в задаче классификации \"user128-vs-All\" в зависимости от размера выборки. Не помешает посмотреть встроенную документацию для *learning_curve*.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"train_sizes = np.linspace(0.25, 1, 20)\n",
"estimator = svm_grid_searcher2.best_estimator_\n",
"n_train, val_train, val_test = learning_curve ''' ВАШ КОД ЗДЕСЬ '''"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plot_learning_curve(val_train, val_test, n_train, \n",
" xlabel='train_size', ylabel='accuracy')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Сделайте выводы о том, помогут ли алгоритму новые размеченные данные при той же постановке задачи.**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Пути улучшения\n",
"- конечно, можно проверить еще кучу алгоритмов, например, Xgboost, но в такой задаче очень маловероятно, что что-то справится лучше линейных методов\n",
"- интересно проверить качество алгоритма на данных, где сессии выделялись не по количеству посещенных сайтов, а по времени, например, 5, 7, 10 и 15 минут. Отдельно стоит отметить данные нашего [соревнования](https://inclass.kaggle.com/c/catch-me-if-you-can-intruder-detection-through-webpage-session-tracking2) \n",
"- опять же, если ресурсы позволяют, можно проверить, насколько хорошо можно решить задачу для 3000 пользователей\n",
"\n",
"\n",
"На следующей неделе мы вспомним про линейные модели, обучаемые стохастическим градиентным спуском, и порадуемся тому, насколько быстрее они работают. Также сделаем первые (или не первые) посылки в [соревновании](https://inclass.kaggle.com/c/catch-me-if-you-can-intruder-detection-through-webpage-session-tracking2) Kaggle Inclass."
]
}
],
"metadata": {
"anaconda-cloud": {},
"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.4"
}
},
"nbformat": 4,
"nbformat_minor": 1
}