Дата выдачи: 20.04.2016
Срок сдачи: 10.05.2016 09:00MSK
Лабораторная работа №4 направлена на применение линейных методов из библиотеки scikit-learn.
Каждая из задач имеет определенную «стоимость» (указана в скобках). Максимально допустимая оценка за работу — 15 баллов. Обратите внимание, что только за реализацию функций без подтверждения их корректной работы оценка выставляться не будет.
Сдавать задание после указанного срока сдачи нельзя. При выставлении неполного балла за задание в связи с наличием ошибок на усмотрение проверяющего предусмотрена возможность исправить задание на указанных в ответном письме условиях.
Задание выполняется САМОСТОЯТЕЛЬНО. «Похожие» решения считаются плагиатом и все задействованные студенты (в том числе те, у кого списали) не могут получить за него больше 0 баллов. Если вы нашли решение какого-то из заданий в открытом источнике, необходимо прислать ссылку на этот источник (скорее всего вы будете не единственным, кто это нашел, поэтому чтобы исключить подозрение в плагиате, необходима ссылка на источник).
Если вы будете решать задание на виртуальной машине, учтите, что его могут видеть все. К тому же недоступность виртуальной машины не является уважительной причиной для продления дедлайна.
Для сдачи задания переименуйте получившийся файл *.ipynb в соответствии со следующим форматом: Username_(group)_Lab4.ipynb, где Username — ваша фамилия на латинице, group — название группы (например, Kozlova_IAD-11_Lab4.ipynb). Далее отправьте этот файл на используемую в Вашей группе почту курса (hse.minor.dm@gmail.com) c темой письма [ИАД-NN] - Лабораторная работа 4 - Фамилия Имя Отчество.
В рамках данного задания мы будем работать с датасетом bikes_rent.csv, в котором для каждого дня имеется календарная информация и погодные условия, характеризующие автоматизированные пункты проката велосипедов, а также число прокатов велосипедов в этот день в автоматизированных пунктах . Последнее мы будем предсказывать; таким образом, мы будем решать задачу регрессии.
Загрузите данные при помощи функции pandas.read_csv. Выведите первые 5 строк, чтобы убедиться в корректном считывании данных.
Для каждого дня проката известны значения следующих признаков:
Итак, у нас есть вещественные, бинарные и номинальные (порядковые) признаки, и со всеми из них можно работать как с вещественными.
Сохраните в отдельную переменную матрицу объект-признак и в другую — столбец с целевым признаком.
(0.5 балла) В начале попробуем посмотреть на признаки. Постройте матрицу коэффициентов корреляции Пирсона между признаками. Для этого можно воспользоваться методом датафрейма corr. Для удобства можно визуализировать ее как hot-map (пример, как это можно сделать, есть в семинаре про визуализацию). Можно ли сказать, что среди признаков есть линейно зависимые? Укажите какие?
(0.5 балла) Выведите средние значения всех признаков. Можно ли сказать, что признаки имеют разный масштаб? В случае положительного ответа стандартизуйте признаки (из признака вычитается среднее и делится на стандартное отклонение), применив функцию scale.
(1 балл) Теперь попробуем обучить модель регрессии. Линейные модели реализованы в модуле sklearn.linear_model. Создайте объект LinearRegression с параметрами по умолчанию, обучите его на всех данных X и ответах y, а затем для каждого признака выведите его название (хранятся в после columns исходного датафрейма) и вес (веса хранятся в переменной coef_ класса регрессора).
Обратите внимание, что веса при линейно-зависимых признаках по модулю значительно больше, чем при других признаках.
Чтобы понять, почему так произошло, вспомним аналитическую формулу, по которой вычисляются веса линейной модели в методе наименьших квадратов:
$w = (X^TX)^{-1} X^T y$.
Если в X есть линейно-зависимые столбцы, матрица $X^TX$ становится вырожденной, и формула перестает быть корректной. Чем более зависимы признаки, тем меньше определитель этой матрицы и тем хуже аппроксимация $Xw \approx y$. Такую ситуацию называют проблемой мультиколлинеарности.
Решение проблемы мультиколлинеарности состоит в регуляризации линейной модели. К оптимизируемому функционалу $||Xw-y||^2$ прибавляют L1 $\left(\sum_{j=1}^d |w_j| \right)$ или L2 норму весов $\left(\sum_{j=1}^d w_j^2 \right)$, умноженную на коэффициент регуляризации $\alpha$. В первом случае метод называется Lasso, а во втором — Ridge.
В отличие от L2-регуляризации, L1 производит отбор признаков путем обнуления весов при некоторых признаках. Объяснение последнему факту было дано на лекции.
Давайте пронаблюдаем, как меняются веса при увеличении коэффициента регуляризации $\alpha$.
(1 балл) Для каждого значения коэффициента регуляризации из alphas создайте регрессор Lasso, указав в качестве параметра соответствующее значение alpha, обучите его на объектах X и ответах y и запишите полученные веса в соответствующую строку матрицы coefs_lasso, а затем проделайте то же самое для регрессора Ridge и переменной coefs_ridge.
alphas = np.arange(1, 500, 50)
coefs_lasso = np.zeros((alphas.shape[0], X.shape[1])) # матрица весов размера (число регрессоров) x (число признаков)
coefs_ridge = np.zeros((alphas.shape[0], X.shape[1]))
Визуализируйте динамику весов при увеличении параметра регуляризации, вызвав следующий код:
plt.figure(figsize=(8, 5))
for coef, feature in zip(coefs_lasso.T, df.columns):
plt.plot(alphas, coef, label=feature, color=np.random.rand(3))
plt.legend(loc="upper right", bbox_to_anchor=(1.4, 0.95))
plt.xlabel("alpha")
plt.ylabel("feature weight")
plt.title("Lasso")
plt.figure(figsize=(8, 5))
for coef, feature in zip(coefs_ridge.T, df.columns):
plt.plot(alphas, coef, label=feature, color=np.random.rand(3))
plt.legend(loc="upper right", bbox_to_anchor=(1.4, 0.95))
plt.xlabel("alpha")
plt.ylabel("feature weight")
plt.title("Ridge")
(2 балла) Ответьте на вопросы ниже.
В этой части работы мы познакомимся с датасетом MNIST, объектами которого являются рукописные изображени цифр. Каждый объект представляет из себя матрицу размером 8х8 (в данных это выглядит как вектор с 64 признаками). Каждый признак — оттенок серого (в шкале от 0 до 16). Например, при визуализации это будет выглядеть примерно следующим образом (каждый квадратик — отдельный объект):
Загрузите данные с помощью функции load_digits.
У загруженного датасета целевая переменная находится в поле target, а сами данные в поле data.
(0.2 балла) Посчитайте сколько различных классов цифр есть в данных, а также сколько в каждом классе содержится объектов.
Для оценивания качества алгоритма будем использовать отложенную выборку. Воспользуйтесь функцией train_test_split чтобы разделить данные на обучающие и тестовые. Важно, чтобы от перезапуска ваше разбиение не менялось, кроме того соотношение классов между собой соранялось. Для этого вам понадобится установить следующие дополнительные значения у данной функции:
Для начала будем решать задачу бинарной классификации, а именно попробуем отделить цифру 8 от всех остальных. Создайте новую переменную, которая будет аналогично переменной target (своя для обучающей и тестовой выборки), в которой будет стоять 1, если соответствующая метка "8" и -1 в остальных случаях.
(0.8 балла) Сколько теперь получилось объектов положительного класса, а сколько — отрицательного? Какая метрика качества из изученных ранее подойдет для данной задачи и почему? Чем плохо использовать, например, Accuracy?
Рассмотрим линейный классификатор: $$ a(x) = sign \langle w, x\rangle $$
Обычно вводят обозначение $M_i = y_i\langle w, x_i \rangle$ — отступ на объекте $x_i$
Целью классификации является минимизиция количества ошибок классификатора, то есть
$Q(w) = \sum_{i=1}^l[M_i(w) < 0] \to \min_{w}$
Это выражение достаточно сложно оптимизировать, поэтому вводять аппроксимацию:
$Q(w) = \sum_{i=1}^l[M_i(w) < 0] \le \tilde{Q}(w)$
В качестве $\tilde{Q}$ можно рассмотреть следующие функции:
Логистическая регрессия реализована в sklearn в классе LogisticRegression. Одним из ее гиперпараметров является коэффициент регуляризации C. Как вы помните, гиперпараметры подбираются с помощью кросс-валидации.
Для начала зафиксируем схему кросс-валидации: будем использовать кросс-валидацию по 5 блокам. Для этого создайте объект KFold, которому необходимо задать размер выборки (обучающей), а также задать следующие параметры:
После этого можно приступить к подбору значения C. Будем перебирать значения по логарифмической шкале, а именно из множества [0.001, 0.01, 0.1, 1.0, 10]. В качестве оптимизируемой метрики выберем AUC-ROC.
В sklearn для логистической регрессии это можно сделать, например, следующим способом: воспользоваться классом LogisticRegressionCV. В этом случае вам необходимо задать следующие параметры:
Чтобы подобрать оптимальное C, вызовите метод fit.
(2 балла) Создайте объект класса LogisticRegressionCV, передав в качестве значения параметра Cs список [0.001, 0.01, 0.1, 1.0, 10], а в качестве cv — созданный ранее объект KFold. Обучите данный классификатор. Каким получилось оптимальное значение C?
Теперь создайте объект класса LogisticRegression со значением C равным оптимальному, найденному выше. Обучите его (используя метод fit), на всей обучающей выборке.
Теперь пришло время посмотреть как полученный классификатор работает на тестовой выборке.
(2 балла) Для оценивания качества построим ROC и Precision-Recall кривые, а так же посчитаем площадь под ними. Для этого вам нужно сделать следующее:
(1 балл) Теперь найдите, какую точность может иметь данный классификатор, чтобы полнота была не менее 0.8. Аналогично найдите какую максимальную полноту будет иметь классификатор при точности не менее 0.9.
А теперь вернемся к исходной многоклассовой задаче. Как известно, удобство sklearn заключается в том, что вам не нужно делать каких-либо модификаций алгоритмов в многоклассовом случае, так как все уже реализовано внутри библиотеки.
(0.5 балла) Обучите на исходной обучающей выборке логистическую регрессию. Постройте предсказания для тестовой выборки, используя метод predict. Посчитайте accuracy на тестовой выборке.
(1.5 балла) Самое интересное — посмотреть на ошибки классификации. Для этого постройте confusion_matrix. Какие цифры путаются чаще всего между собой? Есть ли цифра, на которой на тестовой выборке классификатор ни разу не ошибся?