{ "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 }