<jupyter_start><jupyter_text>Семинар 1 - Первичный анализ данных, визуализация, etc.   0. Intro  0.0. Keeping a fork up to date 0. Нажмите кнопку fork в правом верънем углу интерфейса 1. Клонируйте репозиторий к себе на локальную машину:> `git clone https://github.com/YOUR-USERNAME/ml_mipt_dafe_major.git` 2. Связите вашу копию с оригинальным репозиторием:> `cd into/cloned/fork-repo`> `git remote add upstream https://github.com/ml-dafe/ml_mipt_dafe_major.git`> `git fetch upstream` 3. Обновите ваш репозиторий, чтобы загрузить изменения оригинального репозитория:> `git pull upstream master` 4. После внесения изменения в проект на локальной машине обновите свой репозиторий:> `git add *` - загрузить все изменения> `git commit -m "comment"` - сделать локальный коммит> `git push origin main` - загрузить локальный коммит в репозиторий! не забудьте про файлик .gitignore, чтобы не загружать лишнего.  0.1. Создание окружения Вариант max: [Ubuntu](https://help.ubuntu.ru/wiki/%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D0%BE%D0%B4%D0%B8%D0%BC_%D0%BD%D0%B0_ubuntu-linux_-_%D0%B8%D0%BD%D1%81%D1%82p%D1%83%D0%BA%D1%86%D0%B8%D1%8F_%D0%B4%D0%BB%D1%8F_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F_windows)[Drivers](https://linuxconfig.org/how-to-install-the-nvidia-drivers-on-ubuntu-18-04-bionic-beaver-linux)[CUDA+CUDNN](https://medium.com/@sh.tsang/tutorial-cuda-v10-2-cudnn-v7-6-5-installation-ubuntu-18-04-3d24c157473f)[CUDA alternative](https://developer.nvidia.com/cuda-10.2-download-archive?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1804&target_type=deblocal)[CUDA GUIDE](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html)Anaconda + pycharm (студентам бесплатно про версия) Вариант min:Anaconda> `conda update conda`> `conda create -n ml_env python=3.7`> `conda activate ml_env`> `conda install -n ml_env numpy`> `conda list`> `pip freeze`> `conda env list`> `conda deactivate`> `conda env remove -n ml_env` Вариант poor:Google drive -> загрузить файл -> открыть с помощью -> Google colaboratory<jupyter_code>from google.colab import drive
drive.mount('/content/gdrive/')
!ls ./gdrive/My\ Drive/Colab\ Notebooks<jupyter_output>ls: cannot access './gdrive/My Drive/Colab Notebooks': No such file or directory<jupyter_text>0.2. Jupyter notebook  0.2.1. Markdown[Здесь](https://athena.brynmawr.edu/jupyter/hub/dblank/public/Jupyter%20Notebook%20Users%20Manual.ipynb) представлено подробное руководство по Markdown, широко используемое в jupyter, github и т. д. Вкратце, это позволяет:0. Делать списки1.  Делать заголовки разных масштабов3. писать *текст* самыми **разными** способами4. добавлять [гиперссылки](http://imgs.xkcd.com/comics/the_universal_label.png)* Делать ненумерованные списки    * в     * том        * числе            * и                * вложенные картиночкииспользовать Markdown:    $\left\{\begin{array}{ll}x = 16 \sin^3 (t) \\ y = 13 \cos (t) - 5 \cos (2t) - 2 \cos (3t) - \cos (4t) \\t \in [0, 2 \pi]\end{array}\right.$а также писать такие символы как $pi$ внутри строки.  0.2.2. Горячие клавишиИспользование горячих клавиш позволяет очень cильно облегчить и ускорить работу с любой программой, особенно связанной со вводом текста. В плане горячих клавиш очень продвинутым является текстовый редактор vim. В нем существует отдельный режим, мозволяющий пользоваться горячими клавишами. В Jupyter notebook поддерживается та же концепция. Существуют 2 режима работы: режим ввода и командный режим. Режим ввода отображается зеленой рамкой вокруг активной ячейки, командный режим -- синей. Для того, чтобы переключиться из режима ввода в командный режим необходимо нажать `Esc`, переход в режим редактирования осуществляется по нажатию клавиши `Enter`.**В командном режиме часто используются следующие горячие клавиши:*** `b` -- вставить пустую ячейку после текущей* `a` -- вставить пустую ячейку перед текучей-----* `ctrl + c` -- копировать текущую ячейку* `ctrl + x` -- вырезать ячейку* `ctrl + v` -- вставить ячейку из буфера после текущей-----* `dd` -- удалить текущую ячейку* `z` -- отменить предыдущее действие (в юпитере не последней версии можно отменить ТОЛЬКО ОДНО действие) -----* `m` -- перевести ячейку в режим Markdown* `y` -- перевести ячейку в режим кода* `l` -- отображать номера строк* `o` -- скрыть/показать вывод текущей ячейки-----* `ii` -- остановить выполнение текущей ячейки* `00` -- перезагрузить ядро* `s` -- сохранить notebook-----* `h` -- Показать справку по горячим клавишам**Некоторые сочетания используются в режиме редактирования:*** `Tab` (в  начале строки либо для выделенных строк) -- добавить отступ* `Shift+Tab` (в  начале строки либо для выделенных строк) -- убрать отступ-----* `Tab` -- автодополнение вводимой команды* `Shift+Tab` -- показать docstring введеннной команды-----* `Clrl+/` -- закомментировать выделеные строки-----* `Shift+Enter` -- выполнить текущую ячейку кода и перейти к следующей* `Ctrl+Enter` -- выполнить текущую ячейку кода и остаться на ней* `Alt+Enter` -- выполнить текущую ячейку кода и создать новую Также Jupytr Notebook имеет большое количество встроенных "магических" функций. С некоторыми познакомимся в этом курсе, про другие стоит рассказать сразу.<jupyter_code>%lsmagic<jupyter_output><empty_output><jupyter_text>Выполнение bat/bash комманд:<jupyter_code>!ls<jupyter_output>sample_data<jupyter_text>0.2.3. Замер времени выполнения кода Измерение времени выполнения ячейки кода:<jupyter_code>%%time
a = 352e+11
for i in range(10000):
    a = math.sin(a)<jupyter_output>Wall time: 0 ns<jupyter_text>Время выполнения конкретной строки из блока<jupyter_code>%time a = 352e+10
for i in range(1000):
    a = math.sin(a)<jupyter_output>Wall time: 0 ns<jupyter_text>Замер времени выполнения в цикле<jupyter_code>%timeit a = 352e+10
for i in range(1000):
    a = math.sin(a)<jupyter_output>18.5 ns ± 0.252 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)<jupyter_text>разные фишки jupyter notebook описаны [здесь](https://tproger.ru/translations/how-to-optimize-jupyter-notebook/)  1. Повторение  1.1. NumPy**NumPy** — great Python library for matrix computations. It allows to work [easily] with matrices, arrays, math etc. In addition, it allows (and encourage) vector operations, which are **much** quicker. - [numpy](http://www.numpy.org) - [numpy tutorial](http://cs231n.github.io/python-numpy-tutorial/) - [100 numpy exercises](http://www.labri.fr/perso/nrougier/teaching/numpy.100/)<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>Основной тип  — [numpy.ndarray](http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.array.html). Каждый `ndarray` имеет оси<jupyter_code>vec = np.array([1, 2, 3])
vec.ndim # number of axis
mat = np.array([[1, 2, 3], [4, 5, 6]])
mat.shape<jupyter_output><empty_output><jupyter_text>Создание матриц<jupyter_code>np.zeros((3,)) # Создание матрицы из нулей 
np.ones((3, 4)) # Создание матрицы из единиц
np.identity(3) #Создание единичной матрицы
A = np.arange(2, 20, 3) # Создание вектора с указанием границ и шага
A
A.reshape(2, 3) # Изменение формы 
C = A.reshape(3, -1) # Автоматический подбор размеров матрицы
C
C.T # Транспонирование<jupyter_output><empty_output><jupyter_text>Базовые операции над матрицами<jupyter_code>A = np.arange(9).reshape(3, 3)
B = np.arange(8, 17).reshape(3, 3)
print(A)
print(B)
A+B*2 # Сложение и умножение на константу
A * B #Поэлементное умножение
A.dot(B)
A.dot(B).max(axis=1)<jupyter_output><empty_output><jupyter_text>Индексирование<jupyter_code>A[:]
A[:, 1]
A[:, 1:3]
A = np.arange(81).reshape(9, -1)
A
A[:, 2:6]
A[:, 2:6:3] #Можно добавлять шаг
A[A % 2 == 0]<jupyter_output><empty_output><jupyter_text>1.2. Matplotlib* [matplotlib](http://matplotlib.org)* [matplotlib - 2D and 3D plotting in Python](http://nbviewer.jupyter.org/github/jrjohansson/scientific-python-lectures/blob/master/Lecture-4-Matplotlib.ipynb)* [visualization in pandas](http://pandas.pydata.org/pandas-docs/stable/visualization.html)**Matplotlib** — Great library for visualizations.<jupyter_code>%matplotlib inline
import matplotlib.pyplot as plt
x = np.linspace(1, 10, 20)
fig = plt.figure(figsize=(10, 6))

axes = fig.add_axes([0.1, 0.1, 0.8, 0.8])

axes.plot(x, x ** 2, 'r')
axes.plot(x, x ** 3, 'b*--')

axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('title')
axes.legend([r'$x^2$', 'x^3'], loc = 0)

plt.show()
fig, axes = plt.subplots(nrows=1, ncols=3, figsize = (16, 5))

for pow_num, ax in enumerate(axes):
    ax.plot(x, x ** (pow_num + 1), 'r')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title(r'$y = x^' + str(pow_num + 1)+ r'$', fontsize = 18)
fig.tight_layout() # dealing with intersecting figures
alpha = 0.7
phi_ext = 2 * np.pi * 0.5

def flux_qubit_potential(phi_m, phi_p):
    return 2 + alpha - 2 * np.cos(phi_p) * np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)

phi_m = np.linspace(0, 2 * np.pi, 100)
phi_p = np.linspace(0, 2 * np.pi, 100)
X, Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(14, 6))

ax = fig.add_subplot(111, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0, cmap='jet')<jupyter_output><empty_output><jupyter_text>2. Работа с данными __Источник данных:__ [https://opendata.socrata.com/](https://opendata.socrata.com/Government/Airplane-Crashes-and-Fatalities-Since-1908/q2te-8cvq)__Dataset:__ Airplane Crashes and Fatalities Since 1908Содержит полную историю авиакатастроф по всему миру, с 1908 года-по настоящее время.> `../data/Airplane_Crashes_and_Fatalities_Since_1908.csv`  2.1. Подготовка данных<jupyter_code>import pandas as pd
import numpy as np

import scipy.stats as st

import seaborn as sns
import matplotlib.pyplot as plt
sns.set(palette='deep', style='darkgrid', rc={"figure.figsize": (15, 8)})


import warnings
warnings.simplefilter('ignore')

%matplotlib inline
 !ls
df = pd.read_csv("./gdrive/My Drive/Colab Notebooks/Airplane_Crashes_and_Fatalities_Since_1908.csv")


#Пока не смотрим на этот код: 
df['Time'] = df['Time'].str.replace('c:','')<jupyter_output><empty_output><jupyter_text>- __Date__: Дата инцидента- __Time__: Время инцидента- __Location__: Локация инцидента- __Operator__: Авиакомпания- __Flight __- __Route__- __Type__: Тип разбившегося самолета - __Registration__:- __cn/In__- __Aborad__: Сколько людей было на борту самолета- __Fatalities__: Число погибших (из тех, кто был на борту)- __Ground:__ Число погибших на земле (из тех, кто не был на борту)- __Summary__: Краткое описание инцидента<jupyter_code># Посмотрим на наш датасет, а так же применим поочередно классы .head(), .tail(), .columns
df.head()<jupyter_output><empty_output><jupyter_text>По умолчанию Pandas выводит всего 20 столбцов и 60 строк, поэтому если ваш датафрейм больше, воспользуйтесь функцией set_option:> pd.set_option('display.max_columns', 100)  > pd.set_option('display.max_rows', 100)<jupyter_code># .shape позволяет выводить размер датасета.
print(df.shape[0], 'строк')
print(df.shape[1], 'столбцов')
#сформируем таблицу с типами данных с помощью класса .dtypes:
df_info = pd.DataFrame(df.dtypes,columns=['Type'])
df_info
# Посмотрим уникальные значения Авиаоператоров с помощью.unique() и их кол-во .nunique() 
df['Operator'].nunique()
#Бывает удобнее воспользоваться классом .info()
df.info()<jupyter_output><empty_output><jupyter_text>2.2. Работа с даннымиКак мы видим колонка Date иммет тип "object", хотя pandas умеет работать с типом данных "datetime64"<jupyter_code>#смените тип данных для колонки "Date" с помощью .to_datetime(), обратите внимание на параметры (dayfirst, yearfirst)
#
# Ошибки можно проигнорировать параметром errors = 'coerce'

df['Date'] = pd.to_datetime(df['Date'])
df['Time'] = pd.to_datetime(df['Time'], errors = 'coerce')
df.dtypes<jupyter_output><empty_output><jupyter_text>Что нам дало изменение типа? В частности теперь мы можем доставать значение года (.dt.year), месяца (.dt.month), дня (.dt.day) и даже дня недели(.dt.dayofweek, Понедельник – 0, Воскресенье – 6)Кстати, чтобы добавить колонку, достаточно просто присвоить значения к df['Название новой колонки']<jupyter_code>#Достаньте из 'Date' - Год, месяц, день недели. 

df['year'] = df['Date'].dt.year
df['month'] = df['Date'].dt.month
df['day'] = df['Date'].dt.day
df['day of week'] = df['Date'].dt.dayofweek # Monday = 0, Sunday = 6,

df['Hours'] = df['Time'].dt.hour
df.head(3)<jupyter_output><empty_output><jupyter_text>2.3. Обращение к данным, фильтрация и другое<jupyter_code>#Посмотрите сколько инцидентов было в 2002 году: 
df[df['year'] == 2002].shape[0]
#Посмотрите сколько инцидентов было c кол-вом жертв (суммарно на земле и на борту) больше 200: 
df[df['Fatalities'] + df['Ground'] > 200].shape[0]
# Кроме того мы можем производить любые операции со столбцами складывать/умножать/делить/логарифимировать etc.   
df['all_victims'] = df['Fatalities'] + df['Ground']
# Посомтрите сколько инцидентов было c кол-вом жертв (суммарно на земле и на борту) больше 200 в 2002 году: 
df[(df['year'] == 2002) & (df['all_victims'] > 200)].shape[0]
# Где произошел инцидент? Какой был самолет? Сколько было жертв? 
print('В 2002 году в ', df[(df['year'] == 2002) & (df['all_victims'] > 200)]['Location'].values[0],
      'разбился', df[(df['year'] == 2002) & (df['all_victims'] > 200)]['Type'].values[0], '. '
      'Общее кол-во жертв', df[(df['year'] == 2002) & (df['all_victims'] > 200)]['all_victims'].values[0]
     )
# Самостоятельно прочитать про .loc / .iloc<jupyter_output><empty_output><jupyter_text>2.4. Работа с текстом и пропусками, объединение таблиц<jupyter_code># Посмотрим на столбец 'Location'
df['Location'].head()
# Как видим локация расписана через запятую, попробуем разбить название с помощью .str.split
loc = df['Location'].str.split(',', expand=True)
loc.head()

#кстати в .str есть много всего полезного, например используемый ранее .replace()<jupyter_output><empty_output><jupyter_text>Видно, что у нас появились пропуски, однако чем правее тем более укрупненно можно посмотреть локацию. Пропуски можно удалить с помощью .drop(), однако нам более интересно заполнить их с помощью fillna()Не забывайте, что есть параметр inplace<jupyter_code>loc[3] = loc[3].fillna(loc[2])
loc[3] = loc[3].fillna(loc[1])
loc[3] = loc[3].fillna(loc[0])
loc[3].nunique()
loc.head()
# объединим таблицы с помощью pd.merge()
df_full = pd.merge(df, loc, left_index=True, right_index=True)
df_full.head(2)
# Удалим колонки '0', '1', '2' с помощью .drop() 
# переименуем колонку '3' в  'Country' (по крайней мере мы надеемся, что там страна)
df_full = df_full.drop([0,1,2], axis=1)
df_full.columns.values[19] = 'Country'
df_full.head(3)
# Сделаем признаки: Day_period и Holiday с помощью .apply(lambda x: ...)

def get_day_time(hour):
    return {
          0 <= hour < 6:   'Ночь',
          6 <= hour < 11:  'Утро',
         11 <= hour < 19:  'День',
         19 <= hour < 23:  'Вечер',
         23 <= hour < 25:  'Ночь'
    }[True]
        
df_full['Day_period'] = df_full['Hours'].fillna(0).apply(lambda x: get_day_time(x))
df_full['Holiday'] = df_full['day of week'].fillna(0).apply(lambda x: 1 if x >= 5 else 0) 

# .map на самостоятельное изучение<jupyter_output><empty_output><jupyter_text>2.5. Сводные таблицы, группировка и агрегация данных<jupyter_code># C помощью .groupby посчитайте сумму жертв по годам. Затем отсортируйте их по убыванию и сделайте топ-10 
df_full.groupby('year').sum().sort_values('all_victims', ascending=False).head(10)
# Нарисуйте график all_victims, Aboard, Fatalities для каждого года
df.groupby('year').sum()[['all_victims', 'Ground', 'Fatalities']].plot(rot=45) #kind='bar'
plt.title('Количество жерт по годам')
plt.show()
# Посчитайте кол-во Инцидентов и жертв по годам. На этот раз используйте .pivot_table()

crashes_by_year = pd.pivot_table(df_full, index='year', values=['Aboard','Fatalities','Ground','all_victims'], aggfunc='sum')
crashes_by_year['count'] =  pd.pivot_table(df_full, index='year', values=['all_victims'], aggfunc='count').values.T[0]
crashes_by_year.tail()
# Сколько жертв на инцидент? 
crashes_by_year['victims_on_incident'] = crashes_by_year['all_victims']/crashes_by_year['count']
# существует ли корреляция между всеми праметрами? 
crashes_by_year.corr()
#Отрисуйте heatmap корреляции для более хорошего визульного представления - используйте sns.heatmap() 

sns.heatmap(crashes_by_year.corr(), 
         vmin=-1, vmax=1,annot=True, cmap='RdBu',)
plt.show()<jupyter_output><empty_output><jupyter_text>2.6. Очистка данныхДанные достаточно чистые, в них вряд ли есть какие-то ошибки и не получается с первого взгляда найти выбросы (outliers). Поэтому и очищать особо нечего. ---Но в реальной жизни, ваши данные скорее всего будут полны мусора.Чаще всего нам пришлось бы убирать выбросы, исправлять очевидные ошибки итд.  2.7. Создание фичейЧем сложнее зависимость между фичей и таргетом, тем более сложная модель потребуется, чтобы эту зависимость использовать. Почему бы просто не выбрать семейство самых гибких моделей? Проблема в том, что без большого количества данных для обучения будет происходить overfit. Это значит, что модель выучит зависимости, которые случайно появились в обучающих из-за ограниченного размера выборки. Такая модель будет хорошо работать на обучающей выборке, но будет плохо справляться с реальной задачей.Используя человеческие знания об устройстве мира, мы можем упростить такую зависимость, создав новые фичи. На самом деле, можно даже не использовать человеческие знания, а просто применить какой-нибудь алгоритм. Например, если у нас есть фичи $x_1, x_2, ..., x_n$, то мы можем добавить новые фичи вида $$x_{newij} = x_i x_j, i \ne j$$и понадеяться, что это улучшит предсказания----- Порассуждаем! В данном примере какие фичи наиболее значимые?-- Пример с оценкой стоимости квартиры.  2.8. Работа с категориальными фичамиБольшинство алгоритмов не принимает категориальные фичи в чистом виде и нужно их как-то закодировать.С категориальными фичами в виде строк/булевых значений/etc умеет работать только catboost (библиотека от Яндекса, реализующая градиентный бустинг). Для xgboost и lightgbm же категориальные фичи нужно превратить в числа. Градиентный бустинг в sklearn вообще не умеет по-особенному обрабатывать категориальные фичи и их нужно кодировать как и для других алгоритмов.  One-hot-encodingСамый простой способ закодировать категориальные фичи - one hot encoding. Представьте, что у нас есть категориальная фича day_of_week с возможными значениями > ['Mon', 'Tue', 'Wedn', 'thur', 'fri', 'sat', 'sun']мы можем создать 7 новых бинарные фичей для каждого из столбцов> 'Mon' -> [1, 0, 0, 0, 0, 0, 0]В pandas очень удобно использовать get_dummies для one-hot-encoding<jupyter_code>a = pd.DataFrame.from_dict({'categorical': ['Mon', 'Tue', 'Wedn', 'thur', 'fri', 'sat', 'sun']})
a
pd.get_dummies(a)<jupyter_output><empty_output><jupyter_text>Бонус! Давайте порисуем еще!<jupyter_code>_, axes = plt.subplots(1, 2, sharey=True, figsize=(16,6))

sns.boxplot(x="Day_period", y="Fatalities", data=df_full[df_full['Fatalities'] < 100],  ax=axes[0]);
sns.violinplot(x="Day_period", y="Fatalities", data=df_full[df_full['Fatalities'] < 100], ax=axes[1],
              hue='Holiday');<jupyter_output><empty_output><jupyter_text>Разберём части Boxplot __Черта__ – Медиана  __Коробка__ – Интерквартильный размах (IQR или разница 25% (Q1) и 75% (Q3) перцентили)   __Усы__ – Это интервал $\bigl[ Q_1 - 1.5 \times IQR$, $Q_3 + 1.5 \times IQR \bigr]$  __Точки__ – ВыбросыПодообнее на [Wikipedia]('https://en.wikipedia.org/wiki/Box_plot')<jupyter_code>fig = plt.figure(figsize=(22, 5))
ax1 = fig.add_subplot(121)
sns.distplot(df_full['Fatalities'].dropna(), fit=st.norm, kde=True,ax=ax1, bins=50)
ax1.set_title('Плотность распределения переменной')
ax2 = fig.add_subplot(122)
prob = st.probplot(df_full['Fatalities'].dropna()), dist=st.norm, plot=ax2)
ax2.set_title('Probabilyty plot')
plt.show()<jupyter_output><empty_output><jupyter_text>kNN - метод ближайших соседей<jupyter_code>from sklearn.datasets import load_digits<jupyter_output><empty_output><jupyter_text>Загрузим данные<jupyter_code>data = load_digits()
print(data['DESCR'])
X, y = data.data, data.target
print('В датасете {} объектов и {} признака'.format(X.shape[0], X.shape[1]))<jupyter_output>В датасете 1797 объектов и 64 признака<jupyter_text>Посмотрим на объекты:<jupyter_code>i = np.random.randint(0, X.shape[0])
print('Class name: {}'.format(y[i]))
print(X[i].reshape(8,8))

X[i]
plt.imshow(X[i].reshape(8,8), cmap='gray_r')
plt.show()<jupyter_output>Class name: 2
[[ 0.  0.  2. 12. 16. 10.  0.  0.]
 [ 0.  2. 15. 10.  6. 15.  0.  0.]
 [ 0.  2.  7.  1.  4. 14.  0.  0.]
 [ 0.  0.  0.  0.  9. 10.  0.  0.]
 [ 0.  0.  0.  0. 12.  3.  0.  0.]
 [ 0.  0.  0.  8. 14.  0.  0.  0.]
 [ 0.  0. 15. 16. 15. 10.  5.  0.]
 [ 0.  0.  1.  8.  8. 11. 16.  6.]]<jupyter_text>Посмотрим на баланс классов:<jupyter_code>counts = np.unique(y, return_counts=True)
pd.DataFrame(counts[1], counts[0], columns=['counts']);
# sns.barplot(counts[0], counts[1])
# plt.show()
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.bar(counts[0], counts[1])
plt.show()<jupyter_output><empty_output><jupyter_text>Разделим выборку на две части: обучающую и тестовую<jupyter_code>from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    train_size=0.5,
                                                    test_size=0.5, 
                                                    shuffle=True,
                                                   random_state=18)
X_train.shape, X_test.shape, y_train.shape, y_test.shape<jupyter_output><empty_output><jupyter_text>Метод ближайших соседей<jupyter_code>from sklearn.neighbors import KNeighborsClassifier<jupyter_output><empty_output><jupyter_text>Зададим классификатор:<jupyter_code>knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
knn_predictons = knn.predict(X_test)
preds = pd.DataFrame(y_test, columns=['True'])
preds['knn_pred'] = knn_predictons
preds.head()
# Посмотрим долю правильных ответов:
def accuracy(true, predictions):
    acc = predictions[true == predictions].shape[0]/true.shape[0]
    return acc
accuracy(y_test, knn_predictons)
#Тоже самое средставми sklearn:
from sklearn.metrics import accuracy_score
accuracy_score(y_test, knn_predictons)<jupyter_output><empty_output><jupyter_text>Постройте график зависимости доли верных ответов на тесте от количества соседей (от 1 до 100):<jupyter_code># Ваш код здесь:<jupyter_output><empty_output><jupyter_text>Поиск оптимальных параметров по сетке<jupyter_code>from sklearn.model_selection import GridSearchCV
n = np.linspace(1, 21, 21, dtype=int)
kNN_cv = KNeighborsClassifier(n_neighbors=5)
params = { 
    'metric':['minkowski', 'manhattan'],
    'n_neighbors': n,
         }

gcv = GridSearchCV(kNN_cv, param_grid=params, cv=5, scoring='accuracy')
gcv.fit(X_train, y_train)
def print_cv_results(a, len_gs, params, param_r, param_sep): 
    d = len(params['param_grid'][param_sep])
    ar=np.array(a).reshape(d,len_gs).T
    df=pd.DataFrame(ar)

    pen_par=params['param_grid'][param_sep]
    c_par=params['param_grid'][param_r]
    if type(c_par) != list: 
        c_par = c_par.tolist()
    columns_mapper=dict(zip(range(0, len(pen_par)),pen_par))
    row_mapper=dict(zip(range(0, len(c_par)), c_par))

    df.rename(columns=columns_mapper, index=row_mapper, inplace=True)

    plot = df.plot(title='Mean accuracy rating',grid=True)
    plot.set_xlabel(param_r, fontsize=13)
    plot.set_ylabel('acc', rotation=0, fontsize=13, labelpad=15)
gcv.get_params()
print_cv_results(gcv.cv_results_['mean_test_score'],
                 21, gcv.get_params(), 'n_neighbors','metric')
gcv.best_params_
print('Лучший скор %.4f' % gcv.best_score_)
print('при метрике %(metric)s и %(n_neighbors)s соседей' % gcv.best_params_)<jupyter_output>Лучший скор 0.9833
при метрике minkowski и 1 соседей<jupyter_text>Что получится на тесте?<jupyter_code>accuracy_score(y_test, gcv.predict(X_test))
gcv_preds = pd.DataFrame(gcv.predict(X_test), columns=['kNN'])
gcv_preds['True'] = y_test
gcv_preds<jupyter_output><empty_output><jupyter_text>Посмотрим на те цифры, которые "путает" наш классификатор<jupyter_code>gcv_preds[gcv_preds['True'] != gcv_preds['kNN']]<jupyter_output><empty_output><jupyter_text>Нормализация Так как мы работаем с пикселями изображения - все признаки имеют "одинаковую" значимость.P.S. Проводить нормализацию можно как для всего изображения (матрицы), так и для каждого пикселя отдельно. Проведите нормировку признаков, вычислите точность, сделайте выводы<jupyter_code># Ваш код здесь:<jupyter_output><empty_output><jupyter_text>Проведите стандартизацию признаков, вычислите точность, сделайте выводы<jupyter_code># Ваш код здесь:<jupyter_output><empty_output><jupyter_text>Реализация kNN<jupyter_code>class KNN:

    def __init__(self, k=1):
        self.k = k

    def fit(self, X, y):
        self.train_X = X
        self.train_y = y

    def predict(self, X, num_loops=2):
  
        if num_loops == 0:
            dists = self.compute_distances_no_loops(X)
        elif num_loops == 1:
            dists = self.compute_distances_one_loop(X)
        else:
            dists = self.compute_distances_two_loops(X)

        if self.train_y.dtype == np.bool:
            return self.predict_labels_binary(dists)
        else:
            return self.predict_labels_multiclass(dists)

    def compute_distances_two_loops(self, X):
        
        num_train = self.train_X.shape[0]
        num_test = X.shape[0]
        dists = np.zeros((num_test, num_train), np.float32)
        for i_test in range(num_test):
            for i_train in range(num_train):
                dists[i_test][i_train] = np.sum(abs(self.train_X[i_train] - X[i_test]))
        return dists
    
    def compute_distances_one_loop(self, X):
        
        num_train = self.train_X.shape[0]
        num_test = X.shape[0]
        dists = np.zeros((num_test, num_train), np.float32)
        for i_test in range(num_test):
            dists[i_test] = np.sum(abs(self.train_X - X[i_test]), axis=1)
        return dists

    def compute_distances_no_loops(self, X):
        
        num_train = self.train_X.shape[0]
        num_test = X.shape[0]
        # Using float32 to to save memory - the default is float64
        dists = np.zeros((num_test, num_train), np.float32)
        train_3d = np.transpose(np.tile(self.train_X, (num_test, 1, 1)), (1, 0, 2))
        dists = np.sum(abs(train_3d - X), axis=2)
        return dists.T

    def predict_labels_binary(self, dists):
        
        num_test = dists.shape[0]
        pred = np.zeros(num_test, np.bool)
        for i in range(num_test):
            unique, counts = np.unique(np.take(self.train_y, np.argsort(dists[i])[:self.k]), return_counts=True)
            pred[i] = unique[np.argmax(counts)]
        return pred

    def predict_labels_multiclass(self, dists):
        
        num_test = dists.shape[0]
        num_test = dists.shape[0]
        pred = np.zeros(num_test, np.int)
        for i in range(num_test):            
            unique, counts = np.unique(np.take(self.train_y, np.argsort(dists[i])[:self.k]), return_counts=True)
            pred[i] = unique[np.argmax(counts)]
        return pred
knn = KNN(k=5)
knn.fit(X_train, y_train)
knn_predictons = knn.predict(X_test)
accuracy_score(y_test, knn_predictons)<jupyter_output><empty_output><jupyter_text>Ссылки:- Хороший [обзор основных функций Pandas](https://alexanderdyakonov.files.wordpress.com/2015/04/ama2015_pandas.pdf) от <NAME> (МГУ)- Открытый курс машинного обучения. [Тема 1. Первичный анализ данных с Pandas](https://habr.com/company/ods/blog/322626/)  - Подробная [Документация Pandas](http://pandas.pydata.org/pandas-docs/stable/api.html)- Материал коллеги [PythonNpCourse](https://github.com/Erhil/PythonNpCourse)- Прикладной курс по машинному обучению от ODS [dlcourse.ai](https://dlcourse.ai/)- Deep Learning School [dlschool](https://www.dlschool.org/) Литература: - <NAME>. Learning Pandas<jupyter_code><jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13307039050563196, 'fraction_numerical': 0.02625874995558398, 'mean_word_length': 4.790946502057613, 'pattern_counts': {'":': 1, '<': 163, '<?xml version=': 0, '>': 183, 'https://': 17, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '39', 'dir': 'jupyter-structured-clean-dedup', 'id': '316395', 'license': 'MIT', 'n_tokens_mistral': 12121, 'n_tokens_neox': 12620, 'n_words': 2483, 'path': 'week_00_Intro_and_org/Seminar_00_.ipynb', 'repo_name': 'NataliaPopkova/ml_mipt_dafe_major', 'size': '28164'}