{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pickle\n",
    "import matplotlib.pyplot as plt\n",
    "import re\n",
    "from sklearn.feature_extraction import FeatureHasher\n",
    "from sklearn.cross_validation import train_test_split\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Описание задания\n",
    "\n",
    "Вам предлагается реализовать метод стохастического градиентного спуска для\n",
    "оптимизации функции потерь в логистической регресси в задаче классификации текстов. \n",
    "\n",
    "В исследуемой выборке находятся $8\\,144$ текстов. Каждый текст относится к одному из классов,\n",
    "метка класса $y$  может принимать значения $-1$ (отрицательный класс) и $+1$ (положительный класс).\n",
    "\n",
    "Для генерации признаков будем использовать хэширование слов:\n",
    "1. Выберем число $d$, обозначающее количетсво различных значений, которое может принимать хэш-функция.\n",
    "1. Сопоставим $i$-ому тексту вектор $x_i = (x_i^1, x_i^2, \\dots, x_i^d)$, где число $x_i^k$ обозначает количетво встретившихся в данном тексте слов со значением хэш-функции равным $k$.\n",
    "\n",
    "** Так как значение $d$ может быть достаточно большим мы не будем в явном виде хранить признаковые описания текстов. **\n",
    "\n",
    "Для решения задачи классификации мы будем использовать метод логистической регрессии.\n",
    "Пусть вектор $w = (w_1, w_2, \\dots, w_d)$ вектор параметров нашей модели.\n",
    "В таком случае вероятность отнесения объекта $x$ к положительному классу выражается следующими формулами:\n",
    "\n",
    "$$\n",
    "    p(y = +1 | x) = \\sigma(<w, x>) = \\frac{1}{1 + \\exp{(w_1 x^1 + w_2 x^2 + \\dots + w_d x^d)}}\n",
    "$$\n",
    "\n",
    "Будем относить объект к положительному классу, если вероятность его принадлежности к первому классу превосходит $\\frac{1}{2}$\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "Для настройки параметром будем минимизировать значение логистической функции потерь:\n",
    "\n",
    "\n",
    "$$\n",
    "    Q(w_1, \\dots, w_d) = \\frac{1}{N} \\sum\\limits_{i = 1}^N \\log{\\left[1 + \\exp{\\left(-y_i \\left[w_1 x_i^1 + w_2 x_i^2 + \\dots + w_d x_i^d \\right] \\right)}\\right]}  \\rightarrow \\min \\limits_{w = (w_1, w_2, \\dots, w_d)}\n",
    "$$\n",
    "\n",
    "Частная производная функции $Q$ по параметру $w_k$ вычисляется по следующей формуле:\n",
    "\n",
    "\n",
    "$$\n",
    "    Q(w_1, \\dots, w_d)'_{w_k} = \\frac{1}{N} \\sum\\limits_{i = 1}^N \\frac{-y_i x_i^k}{\\left[1 + \\exp{\\left(y_i \\left[w_1 x_i^1 + w_2 x_i^2 + \\dots + w_d x_i^d \\right] \\right)}\\right]}\n",
    "$$\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Подзадача 0\n",
    "* Загрузите данные"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "data = pickle.load(open('./text_dataset.pkl', 'rb'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Переведите во всех документах все буквы в нижний регистр. \n",
    "* Замените во всех документах символы, не являющиеся буквами и цифрами, на пробелы. Полезные функции: .lower, .isalnum.\n",
    "* Разбейте каждый документ на термы по пробельным символам (пробелы, переносы строки). Полезная функция: .split()\n",
    "* Релизуйте функции hash_texts(text, d), которая принимает список текстов и число $d$ и заменяет слова во всех текстах на значения хэш-функции от этих слов. (Не забудьте взять хэш-функцию по модулю $d$). Выполните хэширование датасета.\n",
    "* Разбейти выборку на тренировочную и тестовую"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Подзадача 1\n",
    "Реализуйте следующие функции:\n",
    "* calc_loss(H, y, w). Функция принимает \n",
    "    * H - хэшированные представления текстов: список списков хешированных представлений текстов\n",
    "    * y - соответствующие метки классов для текстов,\n",
    "    * w - вектор параметров модели.\n",
    "    * И возвращает значение функции потерь.\n",
    "\n",
    "\n",
    "* calc_accuracy(H, y, w). Функция принимает \n",
    "    * H - хэшированные представления текстов: список списков хешированных представлений текстов\n",
    "    * y - соответствующие метки классов для текстов,\n",
    "    * w - вектор параметров модели.\n",
    "    * И возвращает долю верно классифицированных объектов.\n",
    "\n",
    "\n",
    "* SGD(H, y, w_init, alpha, steps=10). Функция принимает\n",
    "    * H - хэшированные представления текстов: список списков хешированных представлений текстов\n",
    "    * y - соответствующие метки классов для текстов,\n",
    "    * w_init - начальный вектор параметров модели,\n",
    "    * alhpha(step) - функцию, принимающую номер текущего шага и возвращающую длинну шага для текущей итерации,\n",
    "    * steps - число шагов, которое необходимо выполнить. \n",
    "    * Функция должна возвращать оптимальный вектор $w$.\n",
    "    \n",
    "Подберите значение параметра $d$ и длину шага, чтобы обученная модель получала не менее 90% \n",
    "точность на тестовой выборке.\n",
    "\n",
    "**В качестве H и y передаются признаки и метки для mini-batch -- случайного подмножества текстов из обучающей выборки**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Подзадача 2\n",
    "Добавьте в модель $L_2$-регуляризацию. Как изменятся формулы пересчёта для SGD? \n",
    "\n",
    "Исправьте все функции так, чтобы добавить в модель $L_2$ регуляризацию."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
