{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "b80ef5b5-3590-f283-cced-6964a306ef59"
      },
      "source": [
        "Just a little look at how prices impact interest_level"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "fae6b375-b481-3c14-85c6-db6653472751"
      },
      "outputs": [],
      "source": [
        "# This Python 3 environment comes with many helpful analytics libraries installed\n",
        "# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n",
        "# For example, here's several helpful packages to load in \n",
        "\n",
        "import numpy as np # linear algebra\n",
        "import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n",
        "\n",
        "# Input data files are available in the \"../input/\" directory.\n",
        "# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n",
        "\n",
        "from subprocess import check_output\n",
        "print(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n",
        "\n",
        "# Any results you write to the current directory are saved as output."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "d4d2ca3e-17eb-5be5-7f96-08f3c9c3d023"
      },
      "source": [
        "## Some useful imports"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "f174d72c-e8c3-eb05-f3ca-75025364dc1b"
      },
      "outputs": [],
      "source": [
        "import seaborn as sns\n",
        "import matplotlib.pyplot as plt\n",
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "18dfccae-6749-96e3-d0a3-2a8978ce08dc"
      },
      "source": [
        "## Read data"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "cf1f67a8-5975-b72e-dab6-3f0669ff1541"
      },
      "outputs": [],
      "source": [
        "train = pd.read_json('../input/train.json').set_index('listing_id')\n",
        "test = pd.read_json('../input/test.json').set_index('listing_id')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "662c19ea-9d94-d0a9-2dc1-295d833a53f9"
      },
      "source": [
        "## Scatter plot:  price vs bedrooms colored by interest_level "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "4c6e02c0-c2a0-fb22-d1cb-bc4ee64faf65"
      },
      "outputs": [],
      "source": [
        "# limit number of bedrooms and prices\n",
        "usable_train =  train[(train.price<10000) & (train.bedrooms<=4)]\n",
        "palette = {\"high\": \"r\", \"low\":\"g\", \"medium\":\"orange\"}\n",
        "plt.figure(figsize=(11,10))\n",
        "for interest in ['low', 'medium', 'high']:\n",
        "    plt.scatter(usable_train[usable_train.interest_level==interest].bedrooms, \n",
        "                usable_train[usable_train.interest_level==interest].price, \n",
        "                c=palette[interest])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "2b064012-2658-0d88-7c1a-f201a05478b6"
      },
      "source": [
        "High interest goes for low prices"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "28e70612-c7c6-4186-bbcd-d7e58ad372d0"
      },
      "source": [
        "## Boxplot gives even better insights "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "eb7ca231-ac9f-96b4-8b80-896ea0bfe13f"
      },
      "outputs": [],
      "source": [
        "plt.figure(figsize=(11,10))\n",
        "sns.boxplot(x=\"bedrooms\", y=\"price\", hue=\"interest_level\", data=usable_train, palette=palette)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "2efea442-9278-7139-86ca-3dde83ef7eb0"
      },
      "source": [
        "## How can we use this ?"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "bf71c80b-242b-bdae-95b3-d34c6ba94bac"
      },
      "outputs": [],
      "source": [
        "def add_median_price(key=None, suffix=\"\", trn_df=None, tst_df=None):\n",
        "    \"\"\"\n",
        "    Compute median prices for renthop dataset.\n",
        "    The function adds 2 columns to the pandas DataFrames : the median prices and a ratio\n",
        "    between nthe actual price of the rent and the median\n",
        "    \n",
        "    :param key: list of columns on which to groupby and compute median prices\n",
        "    :param suffix: string used to suffix the newly created columns/features\n",
        "    :param trn_df: training dataset as a pandas DataFrame\n",
        "    :param tst_df: test dataset as a pandas DataFrame\n",
        "    :return: updated train and test DataFrames\n",
        "\n",
        "    :Example\n",
        "    \n",
        "    train, test = add_median_price(key=['bedrooms', 'bathrooms'], \n",
        "                                   suffix='rooms', \n",
        "                                   trn_df=train, \n",
        "                                   tst_df=test)\n",
        "\n",
        "    \"\"\"\n",
        "    # Set features to be used\n",
        "    median_features = key.copy()\n",
        "    median_features.append('price')\n",
        "    # Concat train and test to find median prices over whole dataset\n",
        "    median_prices = pd.concat([trn_df[median_features], tst_df[median_features]], axis=0)\n",
        "    # Group data by key to compute median prices\n",
        "    medians_by_key = median_prices.groupby(by=key)['price'].median().reset_index()\n",
        "    # Rename median column with provided suffix\n",
        "    medians_by_key.rename(columns={'price': 'median_price_' + suffix}, inplace=True)\n",
        "    # Update data frames, note that merge seems to reset the index\n",
        "    # that's why I reset first and set again the index\n",
        "    trn_df = trn_df.reset_index().merge(medians_by_key, on=key, how='left').set_index('listing_id')\n",
        "    tst_df = tst_df.reset_index().merge(medians_by_key, on=key, how='left').set_index('listing_id')\n",
        "    trn_df['price_to_median_ratio_' + suffix] = trn_df['price'] /trn_df['median_price_' + suffix]\n",
        "    tst_df['price_to_median_ratio_' + suffix] = tst_df['price'] / tst_df['median_price_' + suffix]\n",
        "\n",
        "    return trn_df, tst_df"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "fd415d05-aae4-7426-9f66-b1058ba772b2"
      },
      "source": [
        "## Define classifier over 10 folds"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "32bc8f36-d3ec-ae9d-eb9c-b48a8c215c30"
      },
      "outputs": [],
      "source": [
        "from sklearn.model_selection import StratifiedKFold\n",
        "from sklearn.metrics import log_loss\n",
        "from xgboost import XGBClassifier\n",
        "import time\n",
        "\n",
        "def run_classifier():\n",
        "    n_folds = 3\n",
        "    skf = StratifiedKFold(n_splits=n_folds, shuffle=True, random_state=67594235)\n",
        "    train_features = [ f for f in train.columns \n",
        "                      if (train[f].dtype != 'object') & (f != 'interest_level') ]\n",
        "\n",
        "    target_num_map = {'high': 0, 'medium': 1, 'low': 2}\n",
        "    target = np.array(train['interest_level'].apply(lambda x: target_num_map[x]))\n",
        "\n",
        "    tst_scores = []\n",
        "    tst_rounds = []\n",
        "\n",
        "    data_X = train[train_features].values\n",
        "    start = time.time()\n",
        "    features_imp = np.zeros(len(train_features))\n",
        "    for fold, (trn_idx, tst_idx) in enumerate(skf.split(data_X, target)):\n",
        "        # Create a classifier\n",
        "        clf = XGBClassifier(n_estimators=10000,\n",
        "                            objective='multi:softprob',\n",
        "                            learning_rate=0.3,\n",
        "                            max_depth=3,\n",
        "                            min_child_weight=1,\n",
        "                            subsample=.8,\n",
        "                            colsample_bytree=.9,\n",
        "                            colsample_bylevel=.5,\n",
        "                            gamma=0.0005,\n",
        "                            scale_pos_weight=1,\n",
        "                            base_score=.5,\n",
        "                            reg_lambda=0,\n",
        "                            reg_alpha=0,\n",
        "                            missing=0,\n",
        "                            seed=0)\n",
        "\n",
        "        # Split the data\n",
        "        trn_X = data_X[trn_idx]\n",
        "        trn_Y = target[trn_idx]\n",
        "        tst_X = data_X[tst_idx]\n",
        "        tst_Y = target[tst_idx]\n",
        "\n",
        "        # Train the model\n",
        "        clf.fit(trn_X, trn_Y,\n",
        "            eval_set=[(trn_X, trn_Y), (tst_X, tst_Y)],\n",
        "            verbose=False,\n",
        "            eval_metric='mlogloss',\n",
        "            early_stopping_rounds=50)\n",
        "\n",
        "        # Get features importance\n",
        "        features_imp += clf.feature_importances_\n",
        "\n",
        "        # Predict the data\n",
        "        preds = clf.predict_proba(tst_X, ntree_limit=clf.best_ntree_limit)\n",
        "\n",
        "        tst_scores.append(log_loss(tst_Y, preds))\n",
        "        tst_rounds.append(clf.best_ntree_limit)\n",
        "    \n",
        "        print(\"LogLoss for fold %2d : %.5f\" % (fold+1, log_loss(tst_Y, preds)))\n",
        "\n",
        "    print(\"Average LogLoss : %.5f / %.6f in %4d rounds [%5.1f mn]\"\n",
        "          % (np.mean(tst_scores),\n",
        "             np.std(tst_scores),\n",
        "             np.mean(tst_rounds), (time.time() - start)/60))\n",
        "    \n",
        "    return train_features, features_imp"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "0d75374c-1f5c-0dab-86ca-bec060514883"
      },
      "source": [
        "## Train with basic features"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "eb9251dc-0e88-5657-855d-77f6bb76bc47"
      },
      "outputs": [],
      "source": [
        "for df in (train, test):\n",
        "    df['nb_images'] = df['photos'].apply(len)\n",
        "    df['nb_features'] = df['features'].apply(len)\n",
        "    df['nb_words'] = df['description'].apply(lambda x: len(x.split()))\n",
        "\n",
        "train_features, features_imp = run_classifier()\n",
        "                                             "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "a8f37cc0-f21f-c17e-8806-d0891037c252"
      },
      "source": [
        "## Train with median price over bedrooms"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "8e59b44d-be1c-a1ba-9106-7a061a12f4e2"
      },
      "outputs": [],
      "source": [
        "train, test = add_median_price(key=['bedrooms'],\n",
        "                               suffix=\"bed\",\n",
        "                               trn_df=train, tst_df=test)\n",
        "\n",
        "train_features, features_imp = run_classifier()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "9a3cc9ea-c632-bc49-13f9-8f802335bd02"
      },
      "source": [
        "## Show feature_importances"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "52777661-ba36-c260-e385-5a4608174d3f"
      },
      "outputs": [],
      "source": [
        "imp_df = pd.DataFrame(data={'feature': train_features, \n",
        "                            'importance': features_imp})\n",
        "imp_df.sort_values(by='importance', ascending=False, inplace=True)\n",
        "sns.barplot(x=\"importance\", y=\"feature\", data=imp_df)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "63db44f5-924d-dbf2-2eec-11ec5083ab54"
      },
      "outputs": [],
      "source": [
        ""
      ]
    }
  ],
  "metadata": {
    "_change_revision": 0,
    "_is_fork": false,
    "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.6.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}