{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "878625c3-c4b9-044d-dba1-63712f7555e1"
      },
      "source": [
        "This notebook just uses the four label columns and uses Owen Zhangs leave one out encoding to get an LB of ~0.66.  He explains it better than me so follow the youtube [link][1] and look around the 59 minute mark! \n",
        "\n",
        "\n",
        "  [1]: https://www.youtube.com/watch?v=LgLcfZjNF44"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a5660463-c512-97ea-40c3-48c4c48d748a"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import pandas as pd\n",
        "import xgboost as xgb\n",
        "from sklearn.preprocessing import LabelEncoder"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "40000e68-c2e2-c422-25f5-38afce19c42f"
      },
      "outputs": [],
      "source": [
        "def LeaveOneOut(data1, data2, columnName, useLOO=False, addNoise=False):\n",
        "    grpOutcomes = data1.groupby(columnName)['interest_level'].mean().reset_index()\n",
        "    grpCount = data1.groupby(columnName)['interest_level'].count().reset_index()\n",
        "    grpOutcomes['cnt'] = grpCount.interest_level\n",
        "    if(useLOO):\n",
        "        grpOutcomes = grpOutcomes[grpOutcomes.cnt > 4]\n",
        "    grpOutcomes.drop('cnt', inplace=True, axis=1)\n",
        "    outcomes = data2['interest_level'].values\n",
        "    x = pd.merge(data2[[columnName, 'interest_level']], grpOutcomes,\n",
        "                 suffixes=('x_', ''),\n",
        "                 how='left',\n",
        "                 on=columnName,\n",
        "                 left_index=True)['interest_level']\n",
        "    if(useLOO):\n",
        "        x = ((x*x.shape[0])-outcomes)/(x.shape[0]-1)\n",
        "        if(addNoise):\n",
        "            x = x + np.random.normal(0, .25, x.shape[0])\n",
        "    return x.fillna(x.mean())\n",
        "\n",
        "def runXGB(train_X, train_y, test_X, test_y=None, feature_names=None, seed_val=0, num_rounds=1000):\n",
        "    param = {}\n",
        "    param['objective'] = 'multi:softprob'\n",
        "    param['eta'] = 0.03\n",
        "    param['max_depth'] = 4\n",
        "    param['silent'] = 1\n",
        "    param['num_class'] = 3\n",
        "    param['eval_metric'] = \"mlogloss\"\n",
        "    param['min_child_weight'] = 1\n",
        "    param['subsample'] = 0.7\n",
        "    param['colsample_bytree'] = 0.6\n",
        "    param['seed'] = seed_val\n",
        "    param['seed'] = seed_val\n",
        "    num_rounds = num_rounds\n",
        "\n",
        "    plst = list(param.items())\n",
        "    xgtrain = xgb.DMatrix(train_X, label=train_y)\n",
        "\n",
        "    if test_y is not None:\n",
        "        xgtest = xgb.DMatrix(test_X, label=test_y)\n",
        "        watchlist = [ (xgtrain,'train'), (xgtest, 'test') ]\n",
        "        model = xgb.train(plst, xgtrain, num_rounds, watchlist, early_stopping_rounds=20)\n",
        "    else:\n",
        "        xgtest = xgb.DMatrix(test_X)\n",
        "        model = xgb.train(plst, xgtrain, num_rounds)\n",
        "\n",
        "    pred_test_y = model.predict(xgtest)\n",
        "    return pred_test_y, model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "0c9d98a4-17a5-7f48-ca38-cdf8b0310c91"
      },
      "outputs": [],
      "source": [
        "labels = ['building_id','display_address','street_address','manager_id']\n",
        "train = pd.read_json('../input/train.json')\n",
        "test = pd.read_json('../input/test.json')\n",
        "train.loc[train.interest_level=='low','interest_level'] = 0\n",
        "train.loc[train.interest_level=='medium','interest_level'] = 1\n",
        "train.loc[train.interest_level=='high','interest_level'] = 2\n",
        "train.interest_level = train.interest_level.astype(float)\n",
        "test['interest_level'] = -1"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "52ab21e6-b1f0-45b3-46f7-ecd09906ac27"
      },
      "outputs": [],
      "source": [
        "for f in labels:\n",
        "    lbl = LabelEncoder()\n",
        "    lbl.fit(list(train[f].values) + list(test[f].values))\n",
        "    train[f] = lbl.transform(train[f].values).astype(int)\n",
        "    test[f] = lbl.transform(test[f].values).astype(int)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "46635c78-16a5-2b41-a26c-b4fbcf39b8ae"
      },
      "outputs": [],
      "source": [
        "actualcolumns = []\n",
        "for col in labels: \n",
        "    for lvl in range(3):\n",
        "        kftrain = train.copy()\n",
        "        kftrain.interest_level = (kftrain.interest_level==lvl).astype(int)\n",
        "        train['loo_'+col+'_'+str(lvl)] = LeaveOneOut(kftrain.copy(),\n",
        "                                                     train.copy(),\n",
        "                                                     col, True, True).values\n",
        "        test['loo_'+col+'_'+str(lvl)] = LeaveOneOut(kftrain.copy(),\n",
        "                                                    test.copy(),\n",
        "                                                    col, True, False).values\n",
        "        actualcolumns.extend(['loo_'+col+'_'+str(lvl)])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "8c18f0c1-7490-a55f-a84d-c11771ad6827"
      },
      "outputs": [],
      "source": [
        "preds, model = runXGB(train[actualcolumns],\n",
        "                      train.interest_level,\n",
        "                      test[actualcolumns],\n",
        "                      None,\n",
        "                      feature_names=None,\n",
        "                      seed_val=0,\n",
        "                      num_rounds=500)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "bec481d9-cb1c-5a7d-d945-80a5fa14b953"
      },
      "outputs": [],
      "source": [
        "out_df = pd.DataFrame(preds)\n",
        "out_df.columns = [\"low\", \"medium\", \"high\" ]\n",
        "out_df[\"listing_id\"] = test.listing_id.values\n",
        "out_df = out_df[['high', 'medium', 'low','listing_id']]\n",
        "out_df.to_csv(\"loo_xgb_starter.csv\", index=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "8c064201-5ec5-4b0d-5a8a-548b59642ecc"
      },
      "outputs": [],
      "source": [
        "print(out_df[['low','medium','high']].mean())"
      ]
    }
  ],
  "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
}