#!/usr/bin/env python
# coding: utf-8
# # Майнор по Анализу Данных, Группа ИАД-2
# ## 08/02/2017 Метод kNN, введение в sklearn
# In[1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12,8)
# Для кириллицы на графиках
font = {'family': 'Verdana',
'weight': 'normal'}
plt.rc('font', **font)
# In[2]:
try:
from ipywidgets import interact, IntSlider, fixed
from utils import *
except ImportError:
print u'Так надо'
# # Метод k-ближайших соседей
# Вспомним теоретическую базу метода kNN.
#
# ## Общая постановка задачи МО
# * Множество объектов $O$
# * Каждому объекту $o \in O$ можно поставить в соответствие набор признаков $(x, y)$ где
# * $x \in X$ - вектор описательных признаков
# * $y \in Y$ - целевой признак
# * Существует неизвестная зависимость $f:X \rightarrow Y$
#
# **Задачи:**
# 1. Используя конечный набор примеров $(x, y)$, найти алгоритм (решающую функцию) $a(x) = (\hat{y})$, аппроксимирующую $f(x)$
# 2. Применить алгоритм $a(x)$ на новых объектах
#
# ## Как постросить $a(x)$ из семейства метрических методов (kNN)?
#
# * Гипотеза компактности: "Похожим объектам соответстуют похожие ответы"
# * Необходимо ввести функцию расстояния между объектами (не обязательно метрику)
# * Запоминаем обучающую выборку и используем для расчета расстояния
#
# ### Самые популярные меры расстояния
#
# $$ d(a, b) = \sum\limits_{i=1}^{D}(a_i - b_i)^2 \text{: euclidean distance} $$
#
# $$ d(a, b) = \sum\limits_{i=1}^{D}|a_i - b_i| \text{: manhattan distance} $$
#
# $$ d(a, b) = 1 - \frac{\langle a,b \rangle}{||a||_2\cdot||b||_2} \text{: cosine distance} $$
#
# ### Алгоритм (kNN)
#
# Вход: Обучающая выборка $X=(x_i,y_i)$, мера близости $d(\cdot, \cdot)$ и объект $\tilde{x}$
#
# Найти $k$ ближайших объекта в $X$ c помощью $d(\tilde{x},\cdot)$
# * (регрессия) вернуть среднее значение* $$\hat{y} = \frac{1}{k}\sum\limits_{j=1}^k y_{(j)}$$
# * (классификация) вернуть наиболее частую метку класса $$\hat{y} = \arg \max\limits_{y \in \{-1, 1\}}\sum\limits_{j=1}^k [y_{(j)} == y] $$
# ## Пример для регрессии
# In[3]:
x_true = np.arange(-5, 5, 0.2)
x = x_true + np.random.rand(x_true.shape[0]) - 0.5
y_true = np.sin(x_true)+x_true/3
y = y_true + np.random.rand(x_true.shape[0]) - 0.5
# In[4]:
plt.plot(x_true, y_true, c='g', label='$f(x)$')
plt.scatter(x, y, label='actual data')
plt.xlabel('x')
plt.ylabel('y')
plt.legend(loc=2)
# In[5]:
try:
plot_linreg(x_true, y_true, x, y)
except:
print u'Смотрите на доску'
# In[6]:
try:
fig = interact(plot_knn,
x_true=fixed(x_true), y_true=fixed(y_true), x=fixed(x), y=fixed(y),
k=IntSlider(min=1, max=10, value=1))
except:
print u'Увы, вновь на доске'
# #### Разберемся c sklearn и сами построим такой график
# In[7]:
from sklearn.neighbors import KNeighborsRegressor
knn = KNeighborsRegressor(n_neighbors=5, weights='uniform', metric='euclidean')
knn.fit(x.reshape(-1,1), y) # Обучение (y - истинные значения)
y_hat = knn.predict(x_true.reshape(-1,1)) # Предсказание (y_hat - ответ модели)
# In[8]:
plt.plot(x_true, y_true, c='g', label='$f(x)$')
plt.scatter(x, y, label='actual data')
plt.plot(x_true, y_hat, c='r', label='knn')
plt.xlabel('x')
plt.ylabel('y')
plt.legend(loc=2)
# ## Пример для классификации
# In[9]:
from sklearn.datasets import make_moons
X_moons, y_moons = make_moons(noise=0.3, random_state=1234)
# In[10]:
plt.scatter(X_moons[:,0], X_moons[:,1], c=y_moons, s=200)
plt.xlabel('$x_1$')
plt.ylabel('$x_2$')
# In[11]:
try:
fig = interact(plot_knn_class,
X_moons=fixed(X_moons), y_moons=fixed(y_moons),
k=IntSlider(min=1, max=10, value=1))
except:
print u'Доскааааа'
# #### Задание
#
# Попробуйте сами нарисовать такой график. С этим вам могут помочь функции `np.meshgrid()` и `plt.contourf()`
# In[12]:
X_moons.shape # матрица с признаками
# In[13]:
y_moons.shape # вектор с ответами (классами)
# In[14]:
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=3, metric='euclidean')
knn.fit(X_moons, y_moons)
y_hat = knn.predict(X_moons) # Предсказание на обучающей выборке (бесполезно)
# Получим все возможные точки на плоскости
x1_range = np.linspace(X_moons[:,0].min(), X_moons[:,0].max(), 100)
x2_range = np.linspace(X_moons[:,1].min(), X_moons[:,1].max(), 100)
X1, X2 = np.meshgrid(x1_range, x2_range)
X1 # вектор x1 дублированный по строкам
X2 # вектор x2 дублированный по столбцам
# Мы хотим получить всевозможные пары x1-x2
X_all = np.c_[X1.reshape(-1,1), X2.reshape(-1,1)]
# In[15]:
y_all = knn.predict(X_all)
# In[16]:
plt.contourf(X1, X2, y_all.reshape(100,-1), alpha=0.4) # нарисовали области
plt.scatter(X_moons[:,0], X_moons[:,1],
c=y_moons, s=150) # нарисовали точки
# # Взвешенный kNN
#
# Вход: Обучающая выборка $X=(x_i,y_i)$, мера близости $d(\cdot, \cdot)$ и объект $\tilde{x}$
#
# Найти $k$ ближайших объекта в $X$ c помощью $d(\tilde{x},\cdot)$
#
# * (регрессия) вернуть среднее взвешенное значение* $$\hat{y} = \frac{\sum\limits_{j=1}^k w_{(j)} y_{(j)}}{\sum\limits_{j=1}^k w_{(j)}}$$
# * (классификация) вернуть наиболее частую метку класса c учетом веса $$\hat{y} = \arg \max\limits_{y \in \{-1, 1\}}\sum\limits_{j=1}^k w_{(j)} [y_{(j)} == y] $$
#
# ## Варианты весов
# * $w_{(j)} = \frac{k - j + 1}{k}$
# * $w_{(j)} = 1/d(\tilde{x},x_{(j)})$
# * $w_{(j)} = K(\frac{d(\tilde{x},x_{(j)})}{h}) $ Парзеновское окно (Parzen Window).
# * $K$ - ядро, $h$ - ширина окна
#
# ## Ядра
# * $K(d, h) \propto \exp(- \frac{d^2}{2h^2})$ - gaussian kernel
# * $K(d, h) \propto 1 if x < d$ - tophat kernel
# * $K(d, h) \propto 1 - \frac{d^2}{h^2}$ - epanechnikov kernel
# * $K(d, h) \propto \exp(-d/h)$ - exponential kernel
# * $K(d, h) \propto 1 - d/h if d < h$ - linear kernel
# * $K(d, h) \propto \cos(\frac{\pi d}{2h}) if x < h$ - linear kernel
#
#