{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from scipy.sparse import csr_matrix\n",
    "import sklearn\n",
    "from sklearn.datasets import fetch_20newsgroups\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.metrics import roc_auc_score\n",
    "from sklearn.cross_validation import train_test_split\n",
    "from sklearn.feature_extraction.text import TfidfTransformer, CountVectorizer, HashingVectorizer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. Работа с категориальными признками"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Все эксперименты в этой лабораторной работе предлагается проводить на данных соревнования Amazon Employee Access Challenge: https://www.kaggle.com/c/amazon-employee-access-challenge\n",
    "\n",
    "В данной задаче предлагается предсказать, будет ли одобрен запрос сотрудника на получение доступа к тому или иному ресурсу. Все признаки являются категориальными.\n",
    "\n",
    "Данные доступны по ссылке https://www.dropbox.com/s/q6fbs1vvhd5kvek/amazon.csv\n",
    "\n",
    "Для оценки качества используется ROC-AUC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ACTION</th>\n",
       "      <th>RESOURCE</th>\n",
       "      <th>MGR_ID</th>\n",
       "      <th>ROLE_ROLLUP_1</th>\n",
       "      <th>ROLE_ROLLUP_2</th>\n",
       "      <th>ROLE_DEPTNAME</th>\n",
       "      <th>ROLE_TITLE</th>\n",
       "      <th>ROLE_FAMILY_DESC</th>\n",
       "      <th>ROLE_FAMILY</th>\n",
       "      <th>ROLE_CODE</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>39353</td>\n",
       "      <td>85475</td>\n",
       "      <td>117961</td>\n",
       "      <td>118300</td>\n",
       "      <td>123472</td>\n",
       "      <td>117905</td>\n",
       "      <td>117906</td>\n",
       "      <td>290919</td>\n",
       "      <td>117908</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>17183</td>\n",
       "      <td>1540</td>\n",
       "      <td>117961</td>\n",
       "      <td>118343</td>\n",
       "      <td>123125</td>\n",
       "      <td>118536</td>\n",
       "      <td>118536</td>\n",
       "      <td>308574</td>\n",
       "      <td>118539</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>36724</td>\n",
       "      <td>14457</td>\n",
       "      <td>118219</td>\n",
       "      <td>118220</td>\n",
       "      <td>117884</td>\n",
       "      <td>117879</td>\n",
       "      <td>267952</td>\n",
       "      <td>19721</td>\n",
       "      <td>117880</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>36135</td>\n",
       "      <td>5396</td>\n",
       "      <td>117961</td>\n",
       "      <td>118343</td>\n",
       "      <td>119993</td>\n",
       "      <td>118321</td>\n",
       "      <td>240983</td>\n",
       "      <td>290919</td>\n",
       "      <td>118322</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>42680</td>\n",
       "      <td>5905</td>\n",
       "      <td>117929</td>\n",
       "      <td>117930</td>\n",
       "      <td>119569</td>\n",
       "      <td>119323</td>\n",
       "      <td>123932</td>\n",
       "      <td>19793</td>\n",
       "      <td>119325</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   ACTION  RESOURCE  MGR_ID  ROLE_ROLLUP_1  ROLE_ROLLUP_2  ROLE_DEPTNAME  \\\n",
       "0       1     39353   85475         117961         118300         123472   \n",
       "1       1     17183    1540         117961         118343         123125   \n",
       "2       1     36724   14457         118219         118220         117884   \n",
       "3       1     36135    5396         117961         118343         119993   \n",
       "4       1     42680    5905         117929         117930         119569   \n",
       "\n",
       "   ROLE_TITLE  ROLE_FAMILY_DESC  ROLE_FAMILY  ROLE_CODE  \n",
       "0      117905            117906       290919     117908  \n",
       "1      118536            118536       308574     118539  \n",
       "2      117879            267952        19721     117880  \n",
       "3      118321            240983       290919     118322  \n",
       "4      119323            123932        19793     119325  "
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = pd.read_csv('amazon.csv')\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(32769, 10)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "X_train, X_test, y_train, y_test = train_test_split(data.iloc[:, 1:], data.iloc[:, 0],\n",
    "                                                    test_size=0.3, random_state=241)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Подзадача 1.0 (Опционально)\n",
    "Воспользуйтесь любым известным вам методом классификации для предсказания на данных без предобработки. Какое максимальное качество (roc_auc_score) удаётся получить?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Подзадача 1.1\n",
    "Для каждого признака посчитайте число уникальных значений в датасете. Посчитайте также долю объектов каждого класса.\n",
    "\n",
    "Считайте статистики по оригинальному датасету, а не только по train части. \n",
    "\n",
    "Сохраните результат в dict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Подзадача 1.2\n",
    "Напишите функцию one_hot_decode(), которая преобразовывает dataframe с категориальными признаками в sparse-матрицу (scipy.sparse.csr_matrix) с one_hot представлениями для всех признаков.\n",
    "\n",
    "Для создания разреженной матрицы необходимо воспользоваться наиболее эффективным конструктором csr_matrix, нигде не храня полную матрицу."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[42 19]\n",
      " [17  0]]\n"
     ]
    }
   ],
   "source": [
    "def one_hot_decode(X, vector_size_dict=None):\n",
    "    return csr_matrix(([17, 19, 42], ([1, 0, 0], [0, 1, 0])))\n",
    "\n",
    "print(one_hot_decode(data.iloc[:, 1:]).todense())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Позадача 1.3\n",
    "Обучите логистическую регрессию на получившихся признаках. Попробуйте l1 и l2 резугялирзацию. Постройте график зависимости качества на обучающей и тестовой выборках в зависимости от значения коэффициента регуляризации. (Попробуйте значения от 0.001 до 1000 по лог-шкале) Какое наилучшее качество удалось получить на отложенной выборке?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Позадача 1.4 (Бонус)\n",
    "Напишите функцию feature_hashing_decode(), которая преобразовывает dataframe с категориальными признаками в sparse-матрицу (scipy.sparse.csr_matrix) с one-hot представлениями для всех признаков, где индекс единицы в one-hot представлении задаётся как хэш-функция от значения категориального признака по модулю $h$, где $h$ – индивидуально для каждого признака и задаётся словарём vector_size_dict."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[42 19]\n",
      " [17  0]]\n"
     ]
    }
   ],
   "source": [
    "def feature_hashing_decode(X, vector_size_dict=None):\n",
    "    return csr_matrix(([17, 19, 42], ([1, 0, 0], [0, 1, 0])))\n",
    "\n",
    "print(feature_hashing_decode(data.iloc[:, 1:]).todense())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. Работа с текстами\n",
    "20 newsgroups – задача рубрикации текстов. \n",
    "\n",
    "Смысл в том, чтобы научиться по тексту новостного объвления предсказывать его рубрику. \n",
    "\n",
    "Информация о наличии или отсутствии тех или иных слов в тексте является информативным признаком о его рубрике."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "data = fetch_20newsgroups(remove=('headers', 'footers', 'quotes'))\n",
    "X_train, y_train = data['data'], data['target']\n",
    "data = fetch_20newsgroups(remove=('headers', 'footers', 'quotes'), subset='test')\n",
    "X_test, y_test = data['data'], data['target']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Рубрики"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['alt.atheism',\n",
       " 'comp.graphics',\n",
       " 'comp.os.ms-windows.misc',\n",
       " 'comp.sys.ibm.pc.hardware',\n",
       " 'comp.sys.mac.hardware',\n",
       " 'comp.windows.x',\n",
       " 'misc.forsale',\n",
       " 'rec.autos',\n",
       " 'rec.motorcycles',\n",
       " 'rec.sport.baseball',\n",
       " 'rec.sport.hockey',\n",
       " 'sci.crypt',\n",
       " 'sci.electronics',\n",
       " 'sci.med',\n",
       " 'sci.space',\n",
       " 'soc.religion.christian',\n",
       " 'talk.politics.guns',\n",
       " 'talk.politics.mideast',\n",
       " 'talk.politics.misc',\n",
       " 'talk.religion.misc']"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data['target_names']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Пример пары объект-рубрика в обучающей выборке"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sci.crypt\n",
      "----------\n",
      "\n",
      "Where?  I honestly didn't see any...\n",
      "\n",
      "\n",
      "I disagree, if for no other reason than that there are already other \n",
      "standards in place.  Besides, even if they restrict encryption on the NREN, \n",
      "who cares?  Most of the Internet is commercial anyway.  The NREN is only for \n",
      "geovernment and university research (read the proposals--it's a \"data \n",
      "superhighway\" for Cray users, not anything having to do with the Internet).\n",
      "\n"
     ]
    }
   ],
   "source": [
    "object_idx = 117\n",
    "print(data['target_names'][y[object_idx]])\n",
    "print('----------')\n",
    "print(X[object_idx])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### Задание №2.1\n",
    "\n",
    "1. Перевести во всех документах все буквы в нижний регистр. Заменить во всех документах символы, не являющиеся буквами и цифрами, на пробелы. Полезные функции: .lower, .isalnum.\n",
    "2. Разбить каждый документ на термы по пробельным символам (пробелы, переносы строки). Полезная функция: .split()\n",
    "3. Преобразовать датасет в разреженную матрицу scipy.sparse.csr_matrix, где значение x в позиции (i, j) означает, что в документе i слово j встретилось x раз. (Воспользуйтесь sklearn.feature_extraction.text.CountVectorizer)\n",
    "5. Произвести tf-idf преобразование датасета при помощи sklearn.feature_extraction.text.TfidfTransformer. Используйте параметры по умолчанию.\n",
    "6. Обучите логистическую регрессию на получившихся признаках. Подберите коэффициент регуляризации по значению ошибки на тестовой выборке."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Задание № 2.2 (Бонус)\n",
    "\n",
    "Попробуйте улучшить качество с помощью каких-нибудь ещё признаков, посчитанных по данным. (Попробуйте, например, добавить усреднённые word2vec представления новостных заголовков)"
   ]
  },
  {
   "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
}
