#!/usr/bin/env python
# coding: utf-8
# # Ансамблевые методы.
# # Понижение размерности данных.
# Шестаков А.В. Майнор по анализу данных 10/05/2016
# ## 1) Ансамблевые методы (Ensembles)
# Не обращаясь к формулам, констатируем, что ошибку модели можно выразить через 3 компоненты: $\text{Error} = \text{Bias}^2 + \text{Variance} + \text{Noise}$
# * $\text{Bias}$ (Смещение) - точность модели. Высокое смещение чаще всего означает, что модель недообучена (underfitting).
# * $\text{Variance}$ (Разброс) - чувствительность модели к данным. Высокие разброс чаще всего означает, что модель переобучена (overfitting)
# * $\text{Noise}$ (Шум) - это просто шум.
#
# Для иллюстрации рассмотрим следующую картинку
#
#
# На эти компоненты можно влиять несколькими способами, например, подбирая гиперпараметры моделей.
# *Вопрос: Как меняются Bias и Variance если повышать глубину дерева решений?*
#
# А еще, можно строить комбинации (ансамбли) моделей!
# На лекции в кратце были рассмотрены два способа\алгоритма построения ансамблей.
# ### Bagging
# Bagging - это параллельный способ построения ансамбля.
# 1. Обучающая выборка сэмплируется $k$ раз с помощью *bootstrap'a* (выборка с возвратом)
# 2. На каждом сэмпле обучается отдельная базовая модель
# 3. Ответы моделей усредняются (возможно с весом)
#
#
# **Теоретически, такой подход должен уменьшать Variance составляющую ошибки.**
#
# Самый известный представитель этого метода - модель случайного леса (RandomForest). В данном случае, на каждом сэмпле базовой моделью является дерево решений.
# Если вам нужно за минимальное время построить достаточно точную и устойчивую модель - это ваш вариант.
#
# *Вопрос: Какая доля объектов в среднем попадает в один bootstrap сэмпл?*
# ### Немного интуиции
# #### Классификация
# In[ ]:
import pandas as pd
import numpy as np
from sklearn.datasets import make_circles
from sklearn.datasets import make_moons
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import roc_curve
from sklearn.cross_validation import train_test_split
import matplotlib.pyplot as plt
plt.style.use('ggplot')
get_ipython().run_line_magic('matplotlib', 'inline')
# In[ ]:
X, y = make_circles(n_samples=500, factor=0.1, noise=0.35, random_state=1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
plt.scatter(X_train[:,0], X_train[:,1], c=y_train)
# In[ ]:
dtree = DecisionTreeClassifier(random_state=1)
dtree.fit(X_train, y_train)
# In[ ]:
# Копипаст с предыдущего семинара
x_range = np.linspace(X.min(), X.max(), 100)
xx1, xx2 = np.meshgrid(x_range, x_range)
y_hat = dtree.predict(np.c_[xx1.ravel(), xx2.ravel()])
y_hat = y_hat.reshape(xx1.shape)
plt.contourf(xx1, xx2, y_hat, alpha=0.2)
plt.scatter(X[:,0], X[:,1], c=y)
# In[ ]:
# Выведем распределение выроятностей предсказаний
# Your code here
# In[ ]:
# Теперь попробуем Случайный лес
# Your code here
rf = RandomForestClassifier()
# In[ ]:
# Рисуем предсказания
x_range = np.linspace(X.min(), X.max(), 100)
xx1, xx2 = np.meshgrid(x_range, x_range)
y_hat = rf.predict(np.c_[xx1.ravel(), xx2.ravel()])
y_hat = y_hat.reshape(xx1.shape)
plt.contourf(xx1, xx2, y_hat, alpha=0.2)
plt.scatter(X[:,0], X[:,1], c=y)
# In[ ]:
# Распределение вероятнсстей
# Your code here
# In[ ]:
# Посмотрим, из чего складываются предсказания
for tree in rf.estimators_:
y_hat = tree.predict(np.c_[xx1.ravel(), xx2.ravel()])
y_hat = y_hat.reshape(xx1.shape)
plt.contourf(xx1, xx2, y_hat, alpha=0.02)
plt.scatter(X[:,0], X[:,1], c=y)
# In[ ]:
# Сравните roc-кривые для дерева и леса на тесте
# Your code here
# #### Регрессия
# In[ ]:
X = np.random.uniform(1, 100, 500)
y = np.log(X) + np.random.normal(0, .3, 500)
plt.scatter(X, y)
# In[ ]:
# Обучите модель, изобразите индивидуальные предсказания деревьев
# И устредненное предсказание леса
plt.scatter(X, y)
rf = RandomForestRegressor(n_estimators=10)
rf.fit(X.reshape(-1,1), y)
x_range = np.linspace(X.min(), X.max(), 100)
# Your code here
# ### Boosting
# Boosting - это последовательный способ построения ансамбля.
Мы постоянно работаем с одним и тем же набором данных, **но** на каждом шаге строим новую базовую модель, которая учитывает ошибки предыдущей модели.
#
#
# **Важное ограничение накладывается на базовые модели: они должны быть НЕМНОГО лучше, чем подбрасывание монетки (weak models).** Иначе нас ждет мгновенный overfitting.
#
# **Теоретически, такой подход должен уменьшать Bias составляющую ошибки.**
# ### Вновь интуиция
# #### Классификация
# In[ ]:
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import GradientBoostingRegressor
# In[ ]:
X, y = make_moons(noise=0.1)
plt.scatter(X[:, 0], X[:, 1], c=y)
# In[ ]:
# Обучаем градиентный бустинг на деревьях
gbt = GradientBoostingClassifier(n_estimators=12, max_depth=2, learning_rate=0.3, subsample=1)
gbt.fit(X, y)
# In[ ]:
# Cмотрим, как изменяется предсказания с каждым новым деревом
fig, ax = plt.subplots(4,3, figsize=(15,15))
ax = ax.ravel()
xx1, xx2 = np.meshgrid(np.arange(-1.5, 2.5, 0.1),
np.arange(-1, 1.5, 0.1))
yy = gbt.staged_predict(np.c_[xx1.ravel(), xx2.ravel()])
for i, y_hat in enumerate(yy):
y_hat = y_hat.reshape(xx1.shape)
ax[i].set_title('iteration = %d' % i )
ax[i].contourf(xx1, xx2, y_hat, cmap=plt.cm.Paired)
ax[i].scatter(X[:, 0], X[:, 1], c=y)
# *Вопрос: Какие недостатки\преимущества есть у ансамблевых методов?*
# # 2) Методы понижения размерности данных.
# Большое количество признаков в данных - не всегда хорошо.
# * Проклятие размерности!
# * В признаках может быть шум, а не хотим использовать шумовые взаимосвязи между признаками и прогнозируемой величиной
# * Мультиколлинеарность
# * Далеко не все признаки вносят весомый вклад в предсказание, но если и дальше их "тащить", то это может повлиять на качество
# * Неудобно смотреть на данные
#
# Избавляться от размерности можно методами **отбора признаков (Feature Selection)** и методами **уменьшения разрмености (Feature Reduction)**
#
# ### Feature Selection
# Методы деляться на три группы:
# * Filter methods
# * Признаки рассматриваются независимо друг от друга
# * Изучается индивидуальный "вклад" призника в предсказываемую переменную
# * Быстрое вычисление
# * *Пример?*
# * Wrapper methods
# * Идет отбор группы признаков
# * Может быть оооочень медленным, но качество, обычно, лучше чем у Filter Methods
# * Stepwise feature selection for regression
# * Embedded methods
# * Отбор признаков "зашит" в модель
# * *Пример?*
# #### Filter method - Mutual Information
# $$MI(y,x) = \sum_{x,y} p(x,y) \ln[\frac{p(x,y)}{p(x)p(y)}]$$
# Сколько информации $x$ сообщает об $y$.
# $$NormalizedMI(y,x) = \frac{MI(y,x)}{H(y)}$$
# In[ ]:
from sklearn.metrics import normalized_mutual_info_score as nmi
# In[ ]:
# Размеберем некоторые примеры
# *Вопрос: А что делать если у нас не категориальные а вещественные признаки?*
# #### Wrapper Methods - Recursive Feature Elimination
# При данном подходе из модели последовательно удаляются признаки с наименьшим коэффициентом
# In[ ]:
from sklearn.datasets import make_regression
from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression
# In[ ]:
X, y = make_regression(n_samples=500, n_features=4, n_informative=1,
n_targets=1, tail_strength=0.5, noise=1.0, coef=False, random_state=None)
# In[ ]:
plt.scatter(y, X[:,1])
# In[ ]:
model = LinearRegression()
rfe = RFE(model, n_features_to_select=1, verbose=1)
rfe.fit(X,y)
# In[ ]:
rfe.support_
# ### Feature Reduction
# Методы Feature Reduction производят преобразования признакового пространства, при этом пытаясь сохранить какие-то свойства данных.
#
# PCA (Principal Component Analysis) - делаем такое линейное преобразование признаков, чтобы каждая следующая комплнента содержала в себе наибольшую изменчивость в данных.
#
# Мы уже делали PCA на семинарах (в самом начале, где еще было задание с лицами). Повторимся..
# In[ ]:
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits
# In[ ]:
digits = load_digits()
X = digits.images
y = digits.target
# In[ ]:
plt.imshow(X[2,:], cmap='Greys', interpolation='none')
# In[ ]:
# Перейдем от изображений к матрице объект-признак
# И сделаем PCA в помощью готовой функции в sklearn и SVD
# In[ ]: