<jupyter_start><jupyter_text>Домашнее задание №1: Классификация.  Логистическая регрессия и kNN. *While the machines are being fixed.* Формат сдачи будет объявлен позднее. Либо это будет проверяющая система, либо telegram-бот.  Дедлайны: * ФИВТ, третий курс - 4 марта 23:59* Открытый курс - 7 марта, 23:59  Часть 1. Небольшой numpy-разогрев. (10%)<jupyter_code>import numpy as np
import pandas as pd
# Создайте случайную матрицу A размерами 10 на 10 из целых чисел от 0 до 100
# hint: np.random.randint

A = np.random.randint(0,100,(10,10))
print(A)
print(A.shape)
# Посчитайте средние значения в матрице по столбцам

A.mean(axis=0)
# Транспонируйте матрицу A

A.T
# Перемножьте поэлементно матрицу A и транспонированную матрицу A 

A * A.T
# Посчитайте dot product (результат матричного умножения) матрицы A на саму себя и запишите в матрицу B
# https://en.wikipedia.org/wiki/Dot_product

B = A @ A
print(B)<jupyter_output>[[32057 26097 30926 21037 19194 33512 34318 13824 19412 31700]
 [32539 28735 26640 19473 20087 32966 35402 17261 23673 33313]
 [29141 23418 28772 20992 19541 21760 28608 14164 19900 34411]
 [18464 19877 17900 21217 15072 21462 22278  8340 19922 23404]
 [32480 21051 27106 25504 19349 34283 33692 16658 21110 30539]
 [22233 20189 21412 23438 15181 17235 22713 10410 21653 28312]
 [31546 27603 25454 25328 20995 28391 30438 14444 24180 35759]
 [41938 35369 27081 28809 18876 36561 34288 23275 27461 38470]
 [28606 24583 18828 15052 12447 24883 20277 11745 12659 26918]
 [31105 25613 25624 17978 16596 24087 28184 15902 19475 33846]]<jupyter_text>Часть 2. Логистическая регрессия и kNN. Будем работать с подвыборкой из [данных о типе лесного покрытия из репозитория UCI](http://archive.ics.uci.edu/ml/datasets/Covertype). Доступно 7 различных классов. Каждый объект описывается 54 признаками, 40 из которых являются бинарными. Описание данных доступно по ссылке, а так же в файле `covtype.info.txt`.<jupyter_code>all_data = pd.read_csv('forest_dataset.csv')<jupyter_output><empty_output><jupyter_text>Выделите 20% данных в `delayed_data` в качестве выборки, на которой будет производиться финальное сравнение моделей, в `all_data` поместите оставшиеся 80%.<jupyter_code>train_size = 0.2
ind = int(all_data.shape[0] * train_size)
delayed_data = all_data[:ind]
all_data = all_data[ind:]<jupyter_output><empty_output><jupyter_text>Выделим значения метки класса в переменную `labels`, признаковые описания в переменную `feature_matrix`. Так как данные числовые и не имеют пропусков, переведем их в `numpy`-формат с помощью метода `.values`.<jupyter_code>labels = all_data[all_data.columns[-1]].values
feature_matrix = all_data[all_data.columns[:-1]].values<jupyter_output><empty_output><jupyter_text>2.1 Двуклассовая классификация (10%) Для начала будем работать только с двумя типами лесного покрытия. Обучите линейный классификатор для разделения двух классов. Данные разделите на train и test с помощью `train_test_split`.<jupyter_code>from sklearn.model_selection import train_test_split

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score, accuracy_score
two_class_labels_indices = (labels == 1) + (labels == 2)

two_class_feature_matrix = feature_matrix[two_class_labels_indices]
two_class_labels = labels[two_class_labels_indices]
train_feature_matrix, test_feature_matrix, train_labels, test_labels = train_test_split(two_class_feature_matrix,two_class_labels)<jupyter_output><empty_output><jupyter_text>Обучите логистическую регрессию. Оцените качество классификации на отложенной выборке с помощью `accuracy` и `f1_score` ([Wikipedia](https://en.wikipedia.org/wiki/F1_score)).<jupyter_code>lr_clf = LogisticRegression(solver='liblinear')
lr_clf.fit(train_feature_matrix,train_labels)
print('Accuracy score:',accuracy_score(test_labels,lr_clf.predict(test_feature_matrix)))
print('F1 score:',f1_score(test_labels,lr_clf.predict(test_feature_matrix)))<jupyter_output>Accuracy score: 0.766218585622443
F1 score: 0.7241379310344828<jupyter_text>2.2 Многоклассовая классификация: логистическая регрессия (40%) **Комментарий:***Логистическая регрессия позволяет решать и задачу многоклассовой классификации. Класс ``LogisticRegression`` позвляет это делать двумя способами:* - *1. Стандартный One vs Rest (т.е. каждый класс отделяется от всех других). Параметр `multi_class='ovr'`.*- *2. Используюя кросс-энтропию (оценивается сразу вектор вероятностей принадлежности классам). Параметр `multi_class='multinomial'`.**По умолчанию будем использовать второй способ.* Теперь будем работать со всеми 7 типами покрытия (данные уже находятся в переменных `feature_matrix` и `labels`, если Вы их не переопределили). Разделите выборку на обучающую и тестовую с помощью метода `train_test_split`, используйте значения параметров `test_size=0.2`, `random_state=42`. Обучите логистическую регрессию  на данном датасете.<jupyter_code>from sklearn.preprocessing import StandardScaler

lr_clf = LogisticRegression(multi_class='multinomial',max_iter=1000, tol=0.001)

X_train, X_test, y_train, y_test = train_test_split(feature_matrix,labels,test_size=0.2,random_state=42)
sclr = StandardScaler()
X_train_scaled = sclr.fit_transform(X_train)
X_test_scaled = sclr.transform(X_test)<jupyter_output>C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\validation.py:595: DataConversionWarning: Data with input dtype int64 was converted to float64 by StandardScaler.
  warnings.warn(msg, DataConversionWarning)
C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\validation.py:595: DataConversionWarning: Data with input dtype int64 was converted to float64 by StandardScaler.
  warnings.warn(msg, DataConversionWarning)
C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\validation.py:595: DataConversionWarning: Data with input dtype int64 was converted to float64 by StandardScaler.
  warnings.warn(msg, DataConversionWarning)<jupyter_text>С помощью 5-кратной кросс-валидации (`GridSearchCV`) подберите оптимальное значение параметров `С` и `penalty`. Для параметра `C` используйте набор значений `np.linspace(0.01, 1, 10)`, а для `penalty` - `['l1', 'l2']`. Критерий качества `scoring = 'accuracy'`.<jupyter_code>from sklearn.model_selection import GridSearchCV

param_grid = {
    'C': np.linspace(0.01, 1, 10),
    'solver': ['sag','saga']
}
grid = GridSearchCV(lr_clf,param_grid,cv=5, scoring='accuracy')
grid.fit(X_train_scaled,y_train)
grid.cv_results_<jupyter_output>C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:125: FutureWarning: You are accessing a training score ('split0_train_score'), which will not be available by default any more in 0.21. If you need training scores, please set return_train_score=True
  warnings.warn(*warn_args, **warn_kwargs)
C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:125: FutureWarning: You are accessing a training score ('split1_train_score'), which will not be available by default any more in 0.21. If you need training scores, please set return_train_score=True
  warnings.warn(*warn_args, **warn_kwargs)
C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:125: FutureWarning: You are accessing a training score ('split2_train_score'), which will not be available by default any more in 0.21. If you need training scores, please set return_train_score=True
  warnings.warn(*warn_args, **warn_kwargs)
C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\[...]<jupyter_text>Постройте графики средних значений критерия качества `accuracy` для типов регуляризации `l1` и `l2` в зависимости от коэффициента регуляризации `C`.<jupyter_code>import matplotlib.pyplot as plt

x_c = np.linspace(0.01, 1, 10)
print(grid.cv_results_['mean_test_score'])
y_l1 = grid.cv_results_['mean_test_score'][1::2]
y_l2 = grid.cv_results_['mean_test_score'][::2]
print(y_l1)
print(y_l2)

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16, 5))
axes[0].plot(x_c, y_l1, 'r')
axes[0].set_xlabel('c')
axes[0].set_ylabel('accuracy')
axes[0].set_title(f'accuracy score with L1 regularization', fontsize=16)
axes[1].plot(x_c, y_l2, 'r')
axes[1].set_xlabel('c')
axes[1].set_ylabel('accuracy')
axes[1].set_title(f'accuracy score with L2 regularization', fontsize=16)<jupyter_output>[0.7065625  0.70671875 0.7115625  0.71171875 0.71328125 0.7125
 0.71375    0.71375    0.71453125 0.7134375  0.71515625 0.71359375
 0.71484375 0.71390625 0.715      0.71453125 0.71515625 0.7146875
 0.715      0.7146875 ]
[0.70671875 0.71171875 0.7125     0.71375    0.7134375  0.71359375
 0.71390625 0.71453125 0.7146875  0.7146875 ]
[0.7065625  0.7115625  0.71328125 0.71375    0.71453125 0.71515625
 0.71484375 0.715      0.71515625 0.715     ]<jupyter_text>Проанализируйте полученные графики. Чему равны найденные оптимальные значения параметров `C` и `penalty`?<jupyter_code># Видим, что при увеличении коэффициента регуляризации увеличивается средняя точность на тестовой выборке
print(grid.best_estimator_.C)
print(grid.best_estimator_.solver)<jupyter_output>0.56
sag<jupyter_text>Используя найденные оптимальные значения `C` и `penalty`, обучите логистическую регрессию на обучающей выборке (train) и вычислите вероятности принадлежности к классам для тестовой (test)  выборки (`best_lr_clf.predict_proba`).<jupyter_code>#grid.best_estimator_.fit(X_train_scaled,y_train)
best_estim = LogisticRegression(multi_class='multinomial',max_iter=1000, tol=0.001,solver=grid.best_estimator_.solver,C=grid.best_estimator_.C)
best_estim.fit(X_train_scaled,y_train)
probs_matrix = best_estim.predict_proba(X_test_scaled)<jupyter_output><empty_output><jupyter_text>Для полученной матрицы вычислите усредненные по всем объектам из тестовой выборки значения вероятностей принадлежности к классам. Сравните ее оценкой вероятности принадлежности к классу на основе частот меток классов в обучающей выборке.<jupyter_code>print(probs_matrix.mean(axis=0))
print(np.unique(y_train, return_counts=True)[1]/X_train.shape[0])<jupyter_output>[0.35960571 0.48796319 0.06603779 0.00564878 0.01812216 0.03216734
 0.03045503]
[0.37046875 0.48671875 0.05796875 0.004375   0.01765625 0.0296875
 0.033125  ]<jupyter_text>2.3 Многоклассовая классификация: kNN (30%). Вспомним первое занятие. Обучите на том же датасете `KNeighborsClassifier` из `sklearn`.<jupyter_code>from sklearn.neighbors import KNeighborsClassifier

knn_clsfr = KNeighborsClassifier()<jupyter_output><empty_output><jupyter_text>Попробуйте использовать различные стратегии вычисления весов: `[‘uniform’, ‘distance’]`. Выберите одно из них самостоятельно. Чем обоснован Ваш выбор? Переберите по сетке от `1` до `10` параметр числа соседей. Покажите на графике, как менялись значения критерия качества `accuracy` при изменении числа соседей.<jupyter_code>param_grid_knn = {
    'n_neighbors': np.arange(1,11),
    'weights': ['uniform','distance']
}
grid_knn = GridSearchCV(knn_clsfr,param_grid_knn,cv=5, scoring='accuracy')
grid_knn.fit(X_train_scaled,y_train)
x_knn = np.arange(1,11)
y_dist = grid_knn.cv_results_['mean_test_score'][::2]
y_uni = grid_knn.cv_results_['mean_test_score'][1::2]

fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(16, 5))
axes[0].plot(x_knn, y_dist, 'r')
axes[0].set_xlabel('n_neighbors')
axes[0].set_ylabel('accuracy')
axes[0].set_title(f"Accuracy with distance param 'distance'", fontsize=16)
axes[1].plot(x_knn, y_uni, 'r')
axes[1].set_xlabel('n_neighbors')
axes[1].set_ylabel('accuracy')
axes[1].set_title(f"Accuracy with distance param 'uniform'", fontsize=16)<jupyter_output><empty_output><jupyter_text>Используя найденное оптимальное число соседей, вычислите вероятности принадлежности к классам для тестовой выборки (`.predict_proba`).<jupyter_code>knn_best = KNeighborsClassifier(n_neighbors=grid_knn.best_estimator_.n_neighbors,weights=grid_knn.best_estimator_.weights)
knn_best.fit(X_train_scaled,y_train)
print(knn_best.predict_proba(X_test_scaled))<jupyter_output>[[0.29596422 0.70403578 0.         ... 0.         0.         0.        ]
 [0.23314705 0.         0.         ... 0.         0.         0.76685295]
 [0.         0.92859073 0.         ... 0.         0.07140927 0.        ]
 ...
 [0.         1.         0.         ... 0.         0.         0.        ]
 [0.24610659 0.75389341 0.         ... 0.         0.         0.        ]
 [0.85899162 0.14100838 0.         ... 0.         0.         0.        ]]<jupyter_text>2.4 Сравнение результатов логистической регрессии и kNN (10%).В реальной жизни новые данные становятся доступны с течением времени. Сравните качество Вашей лучшей модели логистической регресии и лучшего kNN  на отложенной выборке `delayed_data`. Какая из моделей показала лучший результат?<jupyter_code>y_delayed = delayed_data[delayed_data.columns[-1]].values
X_delayed = delayed_data[delayed_data.columns[:-1]].values
#print(y_delayed)
#print(X_delayed)
print('KNN prediction:',accuracy_score(y_delayed,knn_best.predict(sclr.transform(X_delayed))))
print('Logreg prediction:',accuracy_score(y_delayed,best_estim.predict(sclr.transform(X_delayed))))<jupyter_output>C:\Users\priboi\Anaconda3\lib\site-packages\sklearn\utils\validation.py:595: DataConversionWarning: Data with input dtype int64 was converted to float64 by StandardScaler.
  warnings.warn(msg, DataConversionWarning)
{'fraction_non_alphanumeric': 0.10338047341753007, 'fraction_numerical': 0.10005293806246691, 'mean_word_length': 5.978364116094987, 'pattern_counts': {'":': 0, '<': 56, '<?xml version=': 0, '>': 56, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '561518', 'license': 'MIT', 'n_tokens_mistral': 6055, 'n_tokens_neox': 5595, 'n_words': 1095, 'path': 'Homeworks/HW_1_Linclass_kNN/HW1_kNN_and_Logistic_regression.ipynb', 'repo_name': 'mrpriboi/ml-mipt', 'size': '13223'}