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