Upload folder using huggingface_hub
Browse files- .gitattributes +2 -35
- e88186124ec611f1/dataset/sample_submission.csv +6 -0
- e88186124ec611f1/dataset/test.csv +0 -0
- e88186124ec611f1/dataset/train.csv +0 -0
- gridlock_solution.ipynb +448 -0
- instructions/instructions.md +95 -0
- solve.py +159 -0
- submission.csv +0 -0
- traffic-management-travel-demand-forecast (1).ipynb +1085 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,2 @@
|
|
| 1 |
-
*.
|
| 2 |
-
*.
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
*.csv filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.ipynb filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
e88186124ec611f1/dataset/sample_submission.csv
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Index,demand
|
| 2 |
+
0,0.090767774072159
|
| 3 |
+
1,0.0898848048932868
|
| 4 |
+
2,0.0070368435076525
|
| 5 |
+
3,0.0790872273785951
|
| 6 |
+
4,0.0546359836658569
|
e88186124ec611f1/dataset/test.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
e88186124ec611f1/dataset/train.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
gridlock_solution.ipynb
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 0,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"colab": {
|
| 6 |
+
"provenance": []
|
| 7 |
+
},
|
| 8 |
+
"kernelspec": {
|
| 9 |
+
"display_name": "Python 3",
|
| 10 |
+
"name": "python3"
|
| 11 |
+
},
|
| 12 |
+
"language_info": {
|
| 13 |
+
"name": "python"
|
| 14 |
+
}
|
| 15 |
+
},
|
| 16 |
+
"cells": [
|
| 17 |
+
{
|
| 18 |
+
"cell_type": "markdown",
|
| 19 |
+
"metadata": {},
|
| 20 |
+
"source": [
|
| 21 |
+
"# Gridlock Hackathon 2.0 — Traffic Demand Prediction\n",
|
| 22 |
+
"\n",
|
| 23 |
+
"**Approach:** LightGBM + XGBoost ensemble with temporal lag features.\n",
|
| 24 |
+
"\n",
|
| 25 |
+
"**Key features:**\n",
|
| 26 |
+
"- Geohash → lat/lon\n",
|
| 27 |
+
"- Cyclical time encoding (sin/cos of hour)\n",
|
| 28 |
+
"- **Lag feature:** same geohash + same timestamp from previous day (day 48)\n",
|
| 29 |
+
"- Per-geohash aggregations: mean, std, median, max demand\n",
|
| 30 |
+
"- Per-geohash per-hour mean demand\n",
|
| 31 |
+
"- Neighbourhood (geo3-prefix) demand aggregations\n",
|
| 32 |
+
"- Temperature (imputed via geohash+hour mean where missing)\n",
|
| 33 |
+
"- Road features: RoadType, NumberofLanes, LargeVehicles, Landmarks, Weather\n",
|
| 34 |
+
"\n",
|
| 35 |
+
"**Evaluation:** `score = max(0, 100 * R2(actual, predicted))`"
|
| 36 |
+
]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"cell_type": "code",
|
| 40 |
+
"execution_count": null,
|
| 41 |
+
"metadata": {},
|
| 42 |
+
"outputs": [],
|
| 43 |
+
"source": [
|
| 44 |
+
"# Install dependencies (Colab)\n",
|
| 45 |
+
"!pip install pygeohash lightgbm xgboost -q"
|
| 46 |
+
]
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"cell_type": "code",
|
| 50 |
+
"execution_count": null,
|
| 51 |
+
"metadata": {},
|
| 52 |
+
"outputs": [],
|
| 53 |
+
"source": [
|
| 54 |
+
"import numpy as np\n",
|
| 55 |
+
"import pandas as pd\n",
|
| 56 |
+
"import pygeohash as pgh\n",
|
| 57 |
+
"from lightgbm import LGBMRegressor\n",
|
| 58 |
+
"from xgboost import XGBRegressor\n",
|
| 59 |
+
"from sklearn.metrics import r2_score\n",
|
| 60 |
+
"import warnings\n",
|
| 61 |
+
"warnings.filterwarnings('ignore')\n",
|
| 62 |
+
"\n",
|
| 63 |
+
"print('Libraries loaded.')"
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"cell_type": "markdown",
|
| 68 |
+
"metadata": {},
|
| 69 |
+
"source": [
|
| 70 |
+
"## 1. Load Data\n",
|
| 71 |
+
"\n",
|
| 72 |
+
"Upload `train.csv` and `test.csv` to Colab or mount Google Drive."
|
| 73 |
+
]
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"cell_type": "code",
|
| 77 |
+
"execution_count": null,
|
| 78 |
+
"metadata": {},
|
| 79 |
+
"outputs": [],
|
| 80 |
+
"source": [
|
| 81 |
+
"# Option A: upload files manually\n",
|
| 82 |
+
"# from google.colab import files\n",
|
| 83 |
+
"# uploaded = files.upload() # upload train.csv and test.csv\n",
|
| 84 |
+
"\n",
|
| 85 |
+
"# Option B: mount Drive\n",
|
| 86 |
+
"# from google.colab import drive\n",
|
| 87 |
+
"# drive.mount('/content/drive')\n",
|
| 88 |
+
"# DATA_PATH = '/content/drive/MyDrive/gridlock/'\n",
|
| 89 |
+
"\n",
|
| 90 |
+
"# Option C: local paths (if running locally)\n",
|
| 91 |
+
"DATA_PATH = 'e88186124ec611f1/dataset/'\n",
|
| 92 |
+
"\n",
|
| 93 |
+
"train = pd.read_csv(DATA_PATH + 'train.csv')\n",
|
| 94 |
+
"test = pd.read_csv(DATA_PATH + 'test.csv')\n",
|
| 95 |
+
"\n",
|
| 96 |
+
"print(f'Train: {train.shape}, Test: {test.shape}')\n",
|
| 97 |
+
"print('Train days:', sorted(train.day.unique()))\n",
|
| 98 |
+
"print('Test days:', sorted(test.day.unique()))\n",
|
| 99 |
+
"train.head()"
|
| 100 |
+
]
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"cell_type": "markdown",
|
| 104 |
+
"metadata": {},
|
| 105 |
+
"source": [
|
| 106 |
+
"## 2. Feature Engineering"
|
| 107 |
+
]
|
| 108 |
+
},
|
| 109 |
+
{
|
| 110 |
+
"cell_type": "code",
|
| 111 |
+
"execution_count": null,
|
| 112 |
+
"metadata": {},
|
| 113 |
+
"outputs": [],
|
| 114 |
+
"source": [
|
| 115 |
+
"def parse_timestamp(df):\n",
|
| 116 |
+
" df = df.copy()\n",
|
| 117 |
+
" df['hour'] = df['timestamp'].map(lambda x: int(x.split(':')[0]))\n",
|
| 118 |
+
" df['minute'] = df['timestamp'].map(lambda x: int(x.split(':')[1]))\n",
|
| 119 |
+
" df['time_min'] = df['day'] * 24 * 60 + df['hour'] * 60 + df['minute']\n",
|
| 120 |
+
" # Cyclical daily time\n",
|
| 121 |
+
" t = (df['hour'] * 60 + df['minute']) / (24 * 60) * 2 * np.pi\n",
|
| 122 |
+
" df['time_sin'] = np.sin(t)\n",
|
| 123 |
+
" df['time_cos'] = np.cos(t)\n",
|
| 124 |
+
" # Cyclical day\n",
|
| 125 |
+
" d = df['day'] / 7 * 2 * np.pi\n",
|
| 126 |
+
" df['day_sin'] = np.sin(d)\n",
|
| 127 |
+
" df['day_cos'] = np.cos(d)\n",
|
| 128 |
+
" return df\n",
|
| 129 |
+
"\n",
|
| 130 |
+
"\n",
|
| 131 |
+
"def decode_geohash(df):\n",
|
| 132 |
+
" df = df.copy()\n",
|
| 133 |
+
" decoded = df['geohash'].map(pgh.decode)\n",
|
| 134 |
+
" df['lat'] = decoded.map(lambda x: x[0])\n",
|
| 135 |
+
" df['lon'] = decoded.map(lambda x: x[1])\n",
|
| 136 |
+
" df['geo3'] = df['geohash'].str[:3]\n",
|
| 137 |
+
" df['geo4'] = df['geohash'].str[:4]\n",
|
| 138 |
+
" return df\n",
|
| 139 |
+
"\n",
|
| 140 |
+
"\n",
|
| 141 |
+
"def encode_categoricals(df):\n",
|
| 142 |
+
" df = df.copy()\n",
|
| 143 |
+
" df['RoadType_enc'] = df['RoadType'].map({'Residential': 0, 'Street': 1, 'Highway': 2}).fillna(-1)\n",
|
| 144 |
+
" df['LargeVehicles_enc'] = (df['LargeVehicles'] == 'Allowed').astype(float)\n",
|
| 145 |
+
" df['Landmarks_enc'] = (df['Landmarks'] == 'Yes').astype(float)\n",
|
| 146 |
+
" df['Weather_enc'] = df['Weather'].map({'Sunny': 0, 'Rainy': 1, 'Foggy': 2, 'Snowy': 3}).fillna(-1)\n",
|
| 147 |
+
" return df\n",
|
| 148 |
+
"\n",
|
| 149 |
+
"\n",
|
| 150 |
+
"train = parse_timestamp(train)\n",
|
| 151 |
+
"train = decode_geohash(train)\n",
|
| 152 |
+
"train = encode_categoricals(train)\n",
|
| 153 |
+
"\n",
|
| 154 |
+
"test = parse_timestamp(test)\n",
|
| 155 |
+
"test = decode_geohash(test)\n",
|
| 156 |
+
"test = encode_categoricals(test)\n",
|
| 157 |
+
"\n",
|
| 158 |
+
"print('Basic features done.')"
|
| 159 |
+
]
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"cell_type": "code",
|
| 163 |
+
"execution_count": null,
|
| 164 |
+
"metadata": {},
|
| 165 |
+
"outputs": [],
|
| 166 |
+
"source": [
|
| 167 |
+
"# ── Temperature imputation ────────────────────────────────────────────────────\n",
|
| 168 |
+
"# Use geohash+hour mean from training data\n",
|
| 169 |
+
"geo_hour_temp = (train.dropna(subset=['Temperature'])\n",
|
| 170 |
+
" .groupby(['geohash', 'hour'])['Temperature']\n",
|
| 171 |
+
" .mean().reset_index()\n",
|
| 172 |
+
" .rename(columns={'Temperature': 'temp_impute'}))\n",
|
| 173 |
+
"\n",
|
| 174 |
+
"day_temp_mean = train.groupby('day')['Temperature'].mean()\n",
|
| 175 |
+
"\n",
|
| 176 |
+
"def impute_temp(df):\n",
|
| 177 |
+
" df = df.merge(geo_hour_temp, on=['geohash', 'hour'], how='left')\n",
|
| 178 |
+
" df['Temperature'] = df['Temperature'].fillna(df['temp_impute'])\n",
|
| 179 |
+
" df['Temperature'] = df['Temperature'].fillna(day_temp_mean.mean())\n",
|
| 180 |
+
" df = df.drop(columns=['temp_impute'])\n",
|
| 181 |
+
" return df\n",
|
| 182 |
+
"\n",
|
| 183 |
+
"train = impute_temp(train)\n",
|
| 184 |
+
"test = impute_temp(test)\n",
|
| 185 |
+
"print(f'Temp NaN remaining - train: {train.Temperature.isna().sum()}, test: {test.Temperature.isna().sum()}')"
|
| 186 |
+
]
|
| 187 |
+
},
|
| 188 |
+
{
|
| 189 |
+
"cell_type": "code",
|
| 190 |
+
"execution_count": null,
|
| 191 |
+
"metadata": {},
|
| 192 |
+
"outputs": [],
|
| 193 |
+
"source": [
|
| 194 |
+
"# ── Lag feature: same geohash + same timestamp, 1 day earlier ────────────────\n",
|
| 195 |
+
"train48 = (train[train['day'] == 48][['geohash', 'timestamp', 'demand']]\n",
|
| 196 |
+
" .rename(columns={'demand': 'demand_lag1d'}))\n",
|
| 197 |
+
"\n",
|
| 198 |
+
"train = train.merge(train48, on=['geohash', 'timestamp'], how='left')\n",
|
| 199 |
+
"test = test.merge(train48, on=['geohash', 'timestamp'], how='left')\n",
|
| 200 |
+
"\n",
|
| 201 |
+
"print(f'Lag1d coverage - train: {train.demand_lag1d.notna().sum()}/{len(train)}, '\n",
|
| 202 |
+
" f'test: {test.demand_lag1d.notna().sum()}/{len(test)}')"
|
| 203 |
+
]
|
| 204 |
+
},
|
| 205 |
+
{
|
| 206 |
+
"cell_type": "code",
|
| 207 |
+
"execution_count": null,
|
| 208 |
+
"metadata": {},
|
| 209 |
+
"outputs": [],
|
| 210 |
+
"source": [
|
| 211 |
+
"# ── Aggregation features (from all train data) ───────────────────────────────\n",
|
| 212 |
+
"\n",
|
| 213 |
+
"# geohash statistics\n",
|
| 214 |
+
"geo_stats = (train.groupby('geohash')['demand']\n",
|
| 215 |
+
" .agg(['mean','std','median','max']).reset_index()\n",
|
| 216 |
+
" .rename(columns={'mean':'geo_mean','std':'geo_std',\n",
|
| 217 |
+
" 'median':'geo_median','max':'geo_max'}))\n",
|
| 218 |
+
"geo_stats['geo_std'] = geo_stats['geo_std'].fillna(0)\n",
|
| 219 |
+
"\n",
|
| 220 |
+
"# geohash + hour mean\n",
|
| 221 |
+
"geo_hour_demand = (train.groupby(['geohash','hour'])['demand']\n",
|
| 222 |
+
" .mean().reset_index()\n",
|
| 223 |
+
" .rename(columns={'demand':'geo_hour_mean'}))\n",
|
| 224 |
+
"\n",
|
| 225 |
+
"# geohash + exact timestamp mean (captures recurring patterns)\n",
|
| 226 |
+
"geo_ts_mean = (train.groupby(['geohash','timestamp'])['demand']\n",
|
| 227 |
+
" .mean().reset_index()\n",
|
| 228 |
+
" .rename(columns={'demand':'geo_ts_mean'}))\n",
|
| 229 |
+
"\n",
|
| 230 |
+
"# geo3 neighbourhood + hour mean\n",
|
| 231 |
+
"geo3_hour = (train.groupby(['geo3','hour'])['demand']\n",
|
| 232 |
+
" .mean().reset_index()\n",
|
| 233 |
+
" .rename(columns={'demand':'geo3_hour_mean'}))\n",
|
| 234 |
+
"\n",
|
| 235 |
+
"# geo3 overall mean\n",
|
| 236 |
+
"geo3_mean = (train.groupby('geo3')['demand']\n",
|
| 237 |
+
" .mean().reset_index()\n",
|
| 238 |
+
" .rename(columns={'demand':'geo3_mean'}))\n",
|
| 239 |
+
"\n",
|
| 240 |
+
"# Hour-of-day global mean (captures daily rhythm)\n",
|
| 241 |
+
"hour_mean = (train.groupby('hour')['demand']\n",
|
| 242 |
+
" .mean().reset_index()\n",
|
| 243 |
+
" .rename(columns={'demand':'hour_global_mean'}))\n",
|
| 244 |
+
"\n",
|
| 245 |
+
"def apply_aggs(df):\n",
|
| 246 |
+
" df = df.merge(geo_stats, on='geohash', how='left')\n",
|
| 247 |
+
" df = df.merge(geo_hour_demand, on=['geohash','hour'], how='left')\n",
|
| 248 |
+
" df = df.merge(geo_ts_mean, on=['geohash','timestamp'], how='left')\n",
|
| 249 |
+
" df = df.merge(geo3_hour, on=['geo3','hour'], how='left')\n",
|
| 250 |
+
" df = df.merge(geo3_mean, on='geo3', how='left')\n",
|
| 251 |
+
" df = df.merge(hour_mean, on='hour', how='left')\n",
|
| 252 |
+
" # Impute missing lag1d using geo_ts_mean\n",
|
| 253 |
+
" df['demand_lag1d'] = df['demand_lag1d'].fillna(df['geo_ts_mean'])\n",
|
| 254 |
+
" return df\n",
|
| 255 |
+
"\n",
|
| 256 |
+
"train = apply_aggs(train)\n",
|
| 257 |
+
"test = apply_aggs(test)\n",
|
| 258 |
+
"\n",
|
| 259 |
+
"print('Aggregation features done.')\n",
|
| 260 |
+
"print(f'Train features: {train.shape[1]}')"
|
| 261 |
+
]
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"cell_type": "markdown",
|
| 265 |
+
"metadata": {},
|
| 266 |
+
"source": [
|
| 267 |
+
"## 3. Model Training"
|
| 268 |
+
]
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"cell_type": "code",
|
| 272 |
+
"execution_count": null,
|
| 273 |
+
"metadata": {},
|
| 274 |
+
"outputs": [],
|
| 275 |
+
"source": [
|
| 276 |
+
"FEATURES = [\n",
|
| 277 |
+
" 'lat', 'lon',\n",
|
| 278 |
+
" 'hour', 'minute', 'day',\n",
|
| 279 |
+
" 'time_sin', 'time_cos', 'day_sin', 'day_cos',\n",
|
| 280 |
+
" 'RoadType_enc', 'NumberofLanes', 'LargeVehicles_enc', 'Landmarks_enc',\n",
|
| 281 |
+
" 'Temperature', 'Weather_enc',\n",
|
| 282 |
+
" 'demand_lag1d',\n",
|
| 283 |
+
" 'geo_mean', 'geo_std', 'geo_median', 'geo_max',\n",
|
| 284 |
+
" 'geo_hour_mean', 'geo_ts_mean', 'geo3_hour_mean', 'geo3_mean',\n",
|
| 285 |
+
" 'hour_global_mean',\n",
|
| 286 |
+
"]\n",
|
| 287 |
+
"\n",
|
| 288 |
+
"X = train[FEATURES].fillna(-1)\n",
|
| 289 |
+
"y = train['demand']\n",
|
| 290 |
+
"X_test = test[FEATURES].fillna(-1)\n",
|
| 291 |
+
"\n",
|
| 292 |
+
"# Cross-val: train on day48, validate on day49\n",
|
| 293 |
+
"mask49 = train['day'] == 49\n",
|
| 294 |
+
"X_tr, y_tr = X[~mask49], y[~mask49]\n",
|
| 295 |
+
"X_va, y_va = X[mask49], y[mask49]\n",
|
| 296 |
+
"\n",
|
| 297 |
+
"print(f'CV split — train: {X_tr.shape}, val: {X_va.shape}')"
|
| 298 |
+
]
|
| 299 |
+
},
|
| 300 |
+
{
|
| 301 |
+
"cell_type": "code",
|
| 302 |
+
"execution_count": null,
|
| 303 |
+
"metadata": {},
|
| 304 |
+
"outputs": [],
|
| 305 |
+
"source": [
|
| 306 |
+
"# ── LightGBM ──────────────────────────────────────────────────────────────────\n",
|
| 307 |
+
"lgbm_params = dict(\n",
|
| 308 |
+
" n_estimators=5000,\n",
|
| 309 |
+
" learning_rate=0.015,\n",
|
| 310 |
+
" num_leaves=255,\n",
|
| 311 |
+
" min_child_samples=15,\n",
|
| 312 |
+
" subsample=0.8, subsample_freq=1,\n",
|
| 313 |
+
" colsample_bytree=0.8,\n",
|
| 314 |
+
" reg_alpha=0.05, reg_lambda=0.1,\n",
|
| 315 |
+
" random_state=42, verbose=-1, n_jobs=-1,\n",
|
| 316 |
+
")\n",
|
| 317 |
+
"\n",
|
| 318 |
+
"lgbm_cv = LGBMRegressor(**lgbm_params)\n",
|
| 319 |
+
"lgbm_cv.fit(X_tr, y_tr)\n",
|
| 320 |
+
"lgbm_cv_pred = lgbm_cv.predict(X_va)\n",
|
| 321 |
+
"lgbm_r2 = r2_score(y_va, lgbm_cv_pred)\n",
|
| 322 |
+
"print(f'LightGBM CV R2: {lgbm_r2:.4f} score: {max(0,100*lgbm_r2):.2f}')"
|
| 323 |
+
]
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"cell_type": "code",
|
| 327 |
+
"execution_count": null,
|
| 328 |
+
"metadata": {},
|
| 329 |
+
"outputs": [],
|
| 330 |
+
"source": [
|
| 331 |
+
"# ── XGBoost ───────────────────────────────────────────────────────────────────\n",
|
| 332 |
+
"xgb_params = dict(\n",
|
| 333 |
+
" n_estimators=5000,\n",
|
| 334 |
+
" learning_rate=0.015,\n",
|
| 335 |
+
" max_depth=8,\n",
|
| 336 |
+
" subsample=0.8,\n",
|
| 337 |
+
" colsample_bytree=0.8,\n",
|
| 338 |
+
" reg_alpha=0.05, reg_lambda=0.1,\n",
|
| 339 |
+
" random_state=42, verbosity=0, n_jobs=-1,\n",
|
| 340 |
+
" tree_method='hist',\n",
|
| 341 |
+
")\n",
|
| 342 |
+
"\n",
|
| 343 |
+
"xgb_cv = XGBRegressor(**xgb_params)\n",
|
| 344 |
+
"xgb_cv.fit(X_tr, y_tr)\n",
|
| 345 |
+
"xgb_cv_pred = xgb_cv.predict(X_va)\n",
|
| 346 |
+
"xgb_r2 = r2_score(y_va, xgb_cv_pred)\n",
|
| 347 |
+
"print(f'XGBoost CV R2: {xgb_r2:.4f} score: {max(0,100*xgb_r2):.2f}')"
|
| 348 |
+
]
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"cell_type": "code",
|
| 352 |
+
"execution_count": null,
|
| 353 |
+
"metadata": {},
|
| 354 |
+
"outputs": [],
|
| 355 |
+
"source": [
|
| 356 |
+
"# ── Ensemble: find best blend weight ─────────────────────────────────────────\n",
|
| 357 |
+
"best_w, best_r2 = 0, -999\n",
|
| 358 |
+
"for w in np.arange(0, 1.05, 0.05):\n",
|
| 359 |
+
" blend = w * lgbm_cv_pred + (1 - w) * xgb_cv_pred\n",
|
| 360 |
+
" r2 = r2_score(y_va, blend)\n",
|
| 361 |
+
" if r2 > best_r2:\n",
|
| 362 |
+
" best_r2, best_w = r2, w\n",
|
| 363 |
+
"\n",
|
| 364 |
+
"print(f'Best blend: {best_w:.2f} * LightGBM + {1-best_w:.2f} * XGBoost')\n",
|
| 365 |
+
"print(f'Ensemble CV R2: {best_r2:.4f} score: {max(0,100*best_r2):.2f}')"
|
| 366 |
+
]
|
| 367 |
+
},
|
| 368 |
+
{
|
| 369 |
+
"cell_type": "code",
|
| 370 |
+
"execution_count": null,
|
| 371 |
+
"metadata": {},
|
| 372 |
+
"outputs": [],
|
| 373 |
+
"source": [
|
| 374 |
+
"# ── Train final models on ALL data ────────────────────────────────────────────\n",
|
| 375 |
+
"print('Training final LightGBM...')\n",
|
| 376 |
+
"lgbm_final = LGBMRegressor(**lgbm_params)\n",
|
| 377 |
+
"lgbm_final.fit(X, y)\n",
|
| 378 |
+
"\n",
|
| 379 |
+
"print('Training final XGBoost...')\n",
|
| 380 |
+
"xgb_final = XGBRegressor(**xgb_params)\n",
|
| 381 |
+
"xgb_final.fit(X, y)\n",
|
| 382 |
+
"\n",
|
| 383 |
+
"# Blend predictions\n",
|
| 384 |
+
"lgbm_test_pred = lgbm_final.predict(X_test)\n",
|
| 385 |
+
"xgb_test_pred = xgb_final.predict(X_test)\n",
|
| 386 |
+
"final_preds = np.clip(\n",
|
| 387 |
+
" best_w * lgbm_test_pred + (1 - best_w) * xgb_test_pred,\n",
|
| 388 |
+
" 0, None\n",
|
| 389 |
+
")\n",
|
| 390 |
+
"\n",
|
| 391 |
+
"print('Done.')"
|
| 392 |
+
]
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"cell_type": "markdown",
|
| 396 |
+
"metadata": {},
|
| 397 |
+
"source": [
|
| 398 |
+
"## 4. Generate Submission"
|
| 399 |
+
]
|
| 400 |
+
},
|
| 401 |
+
{
|
| 402 |
+
"cell_type": "code",
|
| 403 |
+
"execution_count": null,
|
| 404 |
+
"metadata": {},
|
| 405 |
+
"outputs": [],
|
| 406 |
+
"source": [
|
| 407 |
+
"submission = pd.DataFrame({'Index': test['Index'], 'demand': final_preds})\n",
|
| 408 |
+
"submission.to_csv('submission.csv', index=False)\n",
|
| 409 |
+
"print(f'Saved submission.csv shape: {submission.shape}')\n",
|
| 410 |
+
"submission.head(10)"
|
| 411 |
+
]
|
| 412 |
+
},
|
| 413 |
+
{
|
| 414 |
+
"cell_type": "code",
|
| 415 |
+
"execution_count": null,
|
| 416 |
+
"metadata": {},
|
| 417 |
+
"outputs": [],
|
| 418 |
+
"source": [
|
| 419 |
+
"# Download from Colab\n",
|
| 420 |
+
"# from google.colab import files\n",
|
| 421 |
+
"# files.download('submission.csv')"
|
| 422 |
+
]
|
| 423 |
+
},
|
| 424 |
+
{
|
| 425 |
+
"cell_type": "markdown",
|
| 426 |
+
"metadata": {},
|
| 427 |
+
"source": [
|
| 428 |
+
"## 5. Feature Importance"
|
| 429 |
+
]
|
| 430 |
+
},
|
| 431 |
+
{
|
| 432 |
+
"cell_type": "code",
|
| 433 |
+
"execution_count": null,
|
| 434 |
+
"metadata": {},
|
| 435 |
+
"outputs": [],
|
| 436 |
+
"source": [
|
| 437 |
+
"import matplotlib.pyplot as plt\n",
|
| 438 |
+
"\n",
|
| 439 |
+
"fi = pd.Series(lgbm_final.feature_importances_, index=FEATURES).sort_values(ascending=True)\n",
|
| 440 |
+
"fig, ax = plt.subplots(figsize=(8, 8))\n",
|
| 441 |
+
"fi.plot.barh(ax=ax)\n",
|
| 442 |
+
"ax.set_title('LightGBM Feature Importances')\n",
|
| 443 |
+
"plt.tight_layout()\n",
|
| 444 |
+
"plt.show()"
|
| 445 |
+
]
|
| 446 |
+
}
|
| 447 |
+
]
|
| 448 |
+
}
|
instructions/instructions.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Gridlock Hackathon 2.0
|
| 2 |
+
|
| 3 |
+
**Platform:** Flipkart
|
| 4 |
+
**Status:** LIVE
|
| 5 |
+
**Duration:** May 26, 2026, 10:00 PM IST (Asia/Kolkata) – Jun 07, 2026, 11:59 PM IST (Asia/Kolkata)
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## Problem: Traffic Demand Prediction
|
| 10 |
+
|
| 11 |
+
**Max score:** 100
|
| 12 |
+
|
| 13 |
+
### Background
|
| 14 |
+
|
| 15 |
+
Cities worldwide are increasingly turning to AI-powered solutions to tackle traffic congestion. This problem disrupts the smooth flow of transportation and poses a significant barrier to economic growth. To address this challenge effectively, the first step is to understand travel demand and patterns within urban areas comprehensively. By harnessing the power of AI, cities and regions aim to gather critical insights into transportation dynamics. This will enable them to implement data-driven strategies and solutions to alleviate traffic congestion and promote more efficient mobility. Ultimately, this endeavor will foster economic development and prosperity.
|
| 16 |
+
|
| 17 |
+
### Task
|
| 18 |
+
|
| 19 |
+
Design a system that helps us provide valuable insights into passenger travel patterns, booking behavior, and trip cancellations, which can be used for various analyses and predict demand in the travel industry.
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
## Dataset
|
| 24 |
+
|
| 25 |
+
### Files
|
| 26 |
+
|
| 27 |
+
| File | Shape |
|
| 28 |
+
|------|-------|
|
| 29 |
+
| `train.csv` | 77299 × 11 |
|
| 30 |
+
| `test.csv` | 41778 × 10 |
|
| 31 |
+
| `sample_submission.csv` | 5 × 2 |
|
| 32 |
+
|
| 33 |
+
### Variable Descriptions
|
| 34 |
+
|
| 35 |
+
| Column | Description |
|
| 36 |
+
|--------|-------------|
|
| 37 |
+
| `Index` | Unique identification of datapoint |
|
| 38 |
+
| `geohash` | Geographic information regarding a place |
|
| 39 |
+
| `day` | Day when the information is recorded |
|
| 40 |
+
| `timestamp` | Timestamp of the record inserted in the system |
|
| 41 |
+
| `RoadType` | Type of road in the nearby location |
|
| 42 |
+
| `NumberofLanes` | Number of roads/lanes present in the location |
|
| 43 |
+
| `LargeVehicles` | Whether large vehicles are permitted on the specific roads/lanes |
|
| 44 |
+
| `Landmarks` | Whether there are any landmarks near the location |
|
| 45 |
+
| `Temperature` | Temperature of the place |
|
| 46 |
+
| `Weather` | Weather of the place |
|
| 47 |
+
| `demand` | **TARGET** — Demand of traffic at the timestamp (train only) |
|
| 48 |
+
|
| 49 |
+
---
|
| 50 |
+
|
| 51 |
+
## Evaluation Metric
|
| 52 |
+
|
| 53 |
+
```python
|
| 54 |
+
score = max(0, 100 * metrics.r2_score(actual, predicted))
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
- Higher R² → higher score
|
| 58 |
+
- Score clamped to minimum 0 (negative R² counts as 0)
|
| 59 |
+
- Perfect predictions → score of 100
|
| 60 |
+
|
| 61 |
+
---
|
| 62 |
+
|
| 63 |
+
## Submission Requirements
|
| 64 |
+
|
| 65 |
+
- **Prediction file format:** CSV only
|
| 66 |
+
- **Submission size:** 41778 rows × 2 columns
|
| 67 |
+
- **Required columns:**
|
| 68 |
+
- `Index` — correct index values as per the test file
|
| 69 |
+
- `demand` — predicted demand values
|
| 70 |
+
- Column names must match `sample_submission.csv` exactly
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## How to Submit
|
| 75 |
+
|
| 76 |
+
1. Download dataset from the problem page
|
| 77 |
+
2. Solve the problem in your local environment
|
| 78 |
+
3. Save predictions in a `.csv` file
|
| 79 |
+
4. Upload prediction file via **Upload Prediction File → Choose File → Submit & Evaluate**
|
| 80 |
+
5. Upload source code via **Upload Source Files** (zip or tar archive containing):
|
| 81 |
+
- Text file explaining your approach
|
| 82 |
+
- Details about feature engineering
|
| 83 |
+
- Tools used
|
| 84 |
+
- Relevant source files (`.ipynb` + any presentation file)
|
| 85 |
+
6. Add instructions/comments in the **Your Answer** section
|
| 86 |
+
7. Click **Submit**
|
| 87 |
+
|
| 88 |
+
---
|
| 89 |
+
|
| 90 |
+
## Key Notes
|
| 91 |
+
|
| 92 |
+
- **Dataset origin:** Based on the Grab AI for SEA – Traffic Management challenge (public Kaggle dataset). Original Grab data used `geohash6` + `day` + `timestamp` + `demand`.
|
| 93 |
+
- **Scoring:** R² is computed between actual and predicted `demand` on the test set server-side.
|
| 94 |
+
- **Leaderboard:** Live scoring visible on the Leaderboard tab.
|
| 95 |
+
- **Source upload:** Required alongside prediction CSV — judges review approach + feature engineering.
|
solve.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import pygeohash as pgh
|
| 4 |
+
from lightgbm import LGBMRegressor
|
| 5 |
+
from sklearn.metrics import r2_score
|
| 6 |
+
import warnings
|
| 7 |
+
warnings.filterwarnings('ignore')
|
| 8 |
+
|
| 9 |
+
DATA = 'e88186124ec611f1/dataset'
|
| 10 |
+
|
| 11 |
+
print("Loading data...")
|
| 12 |
+
train = pd.read_csv(f'{DATA}/train.csv')
|
| 13 |
+
test = pd.read_csv(f'{DATA}/test.csv')
|
| 14 |
+
|
| 15 |
+
def parse_ts(df):
|
| 16 |
+
df = df.copy()
|
| 17 |
+
df['hour'] = df['timestamp'].map(lambda x: int(x.split(':')[0]))
|
| 18 |
+
df['minute'] = df['timestamp'].map(lambda x: int(x.split(':')[1]))
|
| 19 |
+
df['time_min'] = df['day'] * 24 * 60 + df['hour'] * 60 + df['minute']
|
| 20 |
+
mins_in_day = 24 * 60
|
| 21 |
+
t = (df['hour'] * 60 + df['minute']) / mins_in_day * 2 * np.pi
|
| 22 |
+
df['time_sin'] = np.sin(t)
|
| 23 |
+
df['time_cos'] = np.cos(t)
|
| 24 |
+
# day of week proxy (cyclical)
|
| 25 |
+
d = df['day'] / 7 * 2 * np.pi
|
| 26 |
+
df['day_sin'] = np.sin(d)
|
| 27 |
+
df['day_cos'] = np.cos(d)
|
| 28 |
+
return df
|
| 29 |
+
|
| 30 |
+
def decode_geo(df):
|
| 31 |
+
df = df.copy()
|
| 32 |
+
decoded = df['geohash'].map(lambda x: pgh.decode(x))
|
| 33 |
+
df['lat'] = decoded.map(lambda x: x[0])
|
| 34 |
+
df['lon'] = decoded.map(lambda x: x[1])
|
| 35 |
+
# geohash prefix for neighbor grouping
|
| 36 |
+
df['geo4'] = df['geohash'].str[:4]
|
| 37 |
+
df['geo3'] = df['geohash'].str[:3]
|
| 38 |
+
return df
|
| 39 |
+
|
| 40 |
+
def encode_cats(df):
|
| 41 |
+
df = df.copy()
|
| 42 |
+
road_map = {'Residential': 0, 'Street': 1, 'Highway': 2}
|
| 43 |
+
df['RoadType_enc'] = df['RoadType'].map(road_map).fillna(-1)
|
| 44 |
+
df['LargeVehicles_enc'] = (df['LargeVehicles'] == 'Allowed').astype(float)
|
| 45 |
+
df['Landmarks_enc'] = (df['Landmarks'] == 'Yes').astype(float)
|
| 46 |
+
weather_map = {'Sunny': 0, 'Rainy': 1, 'Foggy': 2, 'Snowy': 3}
|
| 47 |
+
df['Weather_enc'] = df['Weather'].map(weather_map).fillna(-1)
|
| 48 |
+
return df
|
| 49 |
+
|
| 50 |
+
print("Parsing features...")
|
| 51 |
+
train = parse_ts(train)
|
| 52 |
+
train = decode_geo(train)
|
| 53 |
+
train = encode_cats(train)
|
| 54 |
+
test = parse_ts(test)
|
| 55 |
+
test = decode_geo(test)
|
| 56 |
+
test = encode_cats(test)
|
| 57 |
+
|
| 58 |
+
# ── Lag features ──────────────────────────────────────────────────────────────
|
| 59 |
+
train48 = train[train['day'] == 48][['geohash', 'timestamp', 'demand']].rename(
|
| 60 |
+
columns={'demand': 'demand_lag1d'})
|
| 61 |
+
|
| 62 |
+
# Same geohash+timestamp, 1 day earlier
|
| 63 |
+
train = train.merge(train48, on=['geohash', 'timestamp'], how='left')
|
| 64 |
+
test = test.merge(train48, on=['geohash', 'timestamp'], how='left')
|
| 65 |
+
|
| 66 |
+
# ── Static geohash aggregations (from ALL train) ─────────────────────────────
|
| 67 |
+
geo_stats = (train.groupby('geohash')['demand']
|
| 68 |
+
.agg(['mean', 'std', 'median', 'max'])
|
| 69 |
+
.reset_index()
|
| 70 |
+
.rename(columns={'mean':'geo_mean', 'std':'geo_std',
|
| 71 |
+
'median':'geo_median', 'max':'geo_max'}))
|
| 72 |
+
train = train.merge(geo_stats, on='geohash', how='left')
|
| 73 |
+
test = test.merge(geo_stats, on='geohash', how='left')
|
| 74 |
+
|
| 75 |
+
# geohash + hour bucket mean
|
| 76 |
+
geo_hour = (train.groupby(['geohash', 'hour'])['demand']
|
| 77 |
+
.mean().reset_index().rename(columns={'demand': 'geo_hour_mean'}))
|
| 78 |
+
train = train.merge(geo_hour, on=['geohash', 'hour'], how='left')
|
| 79 |
+
test = test.merge(geo_hour, on=['geohash', 'hour'], how='left')
|
| 80 |
+
|
| 81 |
+
# geohash + timestamp exact mean (over train days)
|
| 82 |
+
geo_ts_mean = (train.groupby(['geohash', 'timestamp'])['demand']
|
| 83 |
+
.mean().reset_index().rename(columns={'demand': 'geo_ts_mean'}))
|
| 84 |
+
train = train.merge(geo_ts_mean, on=['geohash', 'timestamp'], how='left')
|
| 85 |
+
test = test.merge(geo_ts_mean, on=['geohash', 'timestamp'], how='left')
|
| 86 |
+
|
| 87 |
+
# geo3 (neighbourhood) hour mean
|
| 88 |
+
geo3_hour = (train.groupby(['geo3', 'hour'])['demand']
|
| 89 |
+
.mean().reset_index().rename(columns={'demand': 'geo3_hour_mean'}))
|
| 90 |
+
train = train.merge(geo3_hour, on=['geo3', 'hour'], how='left')
|
| 91 |
+
test = test.merge(geo3_hour, on=['geo3', 'hour'], how='left')
|
| 92 |
+
|
| 93 |
+
# Impute missing lag1d using geo_ts_mean as proxy
|
| 94 |
+
train['demand_lag1d'] = train['demand_lag1d'].fillna(train['geo_ts_mean'])
|
| 95 |
+
test['demand_lag1d'] = test['demand_lag1d'].fillna(test['geo_ts_mean'])
|
| 96 |
+
|
| 97 |
+
# geo std fill
|
| 98 |
+
train['geo_std'] = train['geo_std'].fillna(0)
|
| 99 |
+
test['geo_std'] = test['geo_std'].fillna(0)
|
| 100 |
+
|
| 101 |
+
FEATURES = [
|
| 102 |
+
'lat', 'lon',
|
| 103 |
+
'hour', 'minute', 'day',
|
| 104 |
+
'time_sin', 'time_cos', 'day_sin', 'day_cos',
|
| 105 |
+
'RoadType_enc', 'NumberofLanes', 'LargeVehicles_enc', 'Landmarks_enc',
|
| 106 |
+
'Temperature', 'Weather_enc',
|
| 107 |
+
'demand_lag1d',
|
| 108 |
+
'geo_mean', 'geo_std', 'geo_median', 'geo_max',
|
| 109 |
+
'geo_hour_mean', 'geo_ts_mean', 'geo3_hour_mean',
|
| 110 |
+
]
|
| 111 |
+
|
| 112 |
+
X_train = train[FEATURES].fillna(-1)
|
| 113 |
+
y_train = train['demand']
|
| 114 |
+
X_test = test[FEATURES].fillna(-1)
|
| 115 |
+
|
| 116 |
+
print(f"Train: {X_train.shape}, Test: {X_test.shape}")
|
| 117 |
+
|
| 118 |
+
# ── CV: train on day48, validate on day49 ────────────────────────────────────
|
| 119 |
+
mask49 = train['day'] == 49
|
| 120 |
+
X_cv_tr, y_cv_tr = X_train[~mask49], y_train[~mask49]
|
| 121 |
+
X_cv_va, y_cv_va = X_train[mask49], y_train[mask49]
|
| 122 |
+
|
| 123 |
+
PARAMS = dict(
|
| 124 |
+
n_estimators=3000,
|
| 125 |
+
learning_rate=0.02,
|
| 126 |
+
num_leaves=255,
|
| 127 |
+
max_depth=-1,
|
| 128 |
+
min_child_samples=15,
|
| 129 |
+
subsample=0.8,
|
| 130 |
+
subsample_freq=1,
|
| 131 |
+
colsample_bytree=0.8,
|
| 132 |
+
reg_alpha=0.05,
|
| 133 |
+
reg_lambda=0.1,
|
| 134 |
+
random_state=42,
|
| 135 |
+
verbose=-1,
|
| 136 |
+
n_jobs=-1,
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
print("\nCV training (day48->day49)...")
|
| 140 |
+
m_cv = LGBMRegressor(**PARAMS)
|
| 141 |
+
m_cv.fit(X_cv_tr, y_cv_tr,
|
| 142 |
+
eval_set=[(X_cv_va, y_cv_va)])
|
| 143 |
+
cv_pred = m_cv.predict(X_cv_va)
|
| 144 |
+
cv_r2 = r2_score(y_cv_va, cv_pred)
|
| 145 |
+
print(f"CV R2: {cv_r2:.4f} | competition score: {max(0, 100*cv_r2):.2f}")
|
| 146 |
+
|
| 147 |
+
print("\nFull training on all data...")
|
| 148 |
+
model = LGBMRegressor(**PARAMS)
|
| 149 |
+
model.fit(X_train, y_train)
|
| 150 |
+
|
| 151 |
+
preds = np.clip(model.predict(X_test), 0, None)
|
| 152 |
+
submission = pd.DataFrame({'Index': test['Index'], 'demand': preds})
|
| 153 |
+
submission.to_csv('submission.csv', index=False)
|
| 154 |
+
print(f"Saved submission.csv ({len(submission)} rows)")
|
| 155 |
+
print(submission.head())
|
| 156 |
+
|
| 157 |
+
fi = pd.Series(model.feature_importances_, index=FEATURES).sort_values(ascending=False)
|
| 158 |
+
print("\nTop feature importances:")
|
| 159 |
+
print(fi.head(15))
|
submission.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
traffic-management-travel-demand-forecast (1).ipynb
ADDED
|
@@ -0,0 +1,1085 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"## Introduction\n",
|
| 8 |
+
"This notebook is a submission to **Grab AI For Sea Challenge - Traffic Management**, to forecast travel demand based on historical Grab bookings. \n",
|
| 9 |
+
"Challenge website: https://www.aiforsea.com/traffic-management\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"There are **four parts** in this notebook:\n",
|
| 12 |
+
"* **Data cleaning & preprocessing**\n",
|
| 13 |
+
"* **Model selection: Random Forest vs. XGBoost**\n",
|
| 14 |
+
"* **Define a function to predict demands of T+1, ..., T+5 using known data till T**\n",
|
| 15 |
+
"* **Predict demands of T+1, ..., T+5 using test data.** \n",
|
| 16 |
+
"\n",
|
| 17 |
+
"The test dataset can start from any time period after the timeframe of the training dataset. My model will use features from the test dataset ending at timestamp T and predict T+1 to T+5 for all the geohashes which appeared in the training dataset. \n",
|
| 18 |
+
"\n",
|
| 19 |
+
"Each time interval in this challenge is 15 minutes.\n",
|
| 20 |
+
"\n",
|
| 21 |
+
"**For evaluators**: please uncomment the code in Part 4 and fill in the link of test dataset. The code will produce a CSV file containing the demand forecasts for T+1 to T+5 for all the geohashes from the training set. Please run all codes in this notebook to avoid any errors. "
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"cell_type": "code",
|
| 26 |
+
"execution_count": 1,
|
| 27 |
+
"metadata": {
|
| 28 |
+
"_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
|
| 29 |
+
"_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5"
|
| 30 |
+
},
|
| 31 |
+
"outputs": [
|
| 32 |
+
{
|
| 33 |
+
"name": "stdout",
|
| 34 |
+
"output_type": "stream",
|
| 35 |
+
"text": [
|
| 36 |
+
"['training.csv']\n"
|
| 37 |
+
]
|
| 38 |
+
}
|
| 39 |
+
],
|
| 40 |
+
"source": [
|
| 41 |
+
"# This Python 3 environment comes with many helpful analytics libraries installed\n",
|
| 42 |
+
"# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n",
|
| 43 |
+
"# For example, here's several helpful packages to load in \n",
|
| 44 |
+
"\n",
|
| 45 |
+
"import numpy as np # linear algebra\n",
|
| 46 |
+
"import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n",
|
| 47 |
+
"\n",
|
| 48 |
+
"# Input data files are available in the \"../input/\" directory.\n",
|
| 49 |
+
"# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n",
|
| 50 |
+
"\n",
|
| 51 |
+
"import os\n",
|
| 52 |
+
"print(os.listdir(\"../input\"))\n",
|
| 53 |
+
"\n",
|
| 54 |
+
"# Any results you write to the current directory are saved as output."
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"cell_type": "markdown",
|
| 59 |
+
"metadata": {},
|
| 60 |
+
"source": [
|
| 61 |
+
"## Part 1 - Data Cleaning & Preprocessing"
|
| 62 |
+
]
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"cell_type": "markdown",
|
| 66 |
+
"metadata": {},
|
| 67 |
+
"source": [
|
| 68 |
+
"Take a look at training set:"
|
| 69 |
+
]
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"cell_type": "code",
|
| 73 |
+
"execution_count": 2,
|
| 74 |
+
"metadata": {
|
| 75 |
+
"_cell_guid": "79c7e3d0-c299-4dcb-8224-4455121ee9b0",
|
| 76 |
+
"_uuid": "d629ff2d2480ee46fbb7e2d37f6b5fab8052498a"
|
| 77 |
+
},
|
| 78 |
+
"outputs": [
|
| 79 |
+
{
|
| 80 |
+
"data": {
|
| 81 |
+
"text/html": [
|
| 82 |
+
"<div>\n",
|
| 83 |
+
"<style scoped>\n",
|
| 84 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 85 |
+
" vertical-align: middle;\n",
|
| 86 |
+
" }\n",
|
| 87 |
+
"\n",
|
| 88 |
+
" .dataframe tbody tr th {\n",
|
| 89 |
+
" vertical-align: top;\n",
|
| 90 |
+
" }\n",
|
| 91 |
+
"\n",
|
| 92 |
+
" .dataframe thead th {\n",
|
| 93 |
+
" text-align: right;\n",
|
| 94 |
+
" }\n",
|
| 95 |
+
"</style>\n",
|
| 96 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 97 |
+
" <thead>\n",
|
| 98 |
+
" <tr style=\"text-align: right;\">\n",
|
| 99 |
+
" <th></th>\n",
|
| 100 |
+
" <th>geohash6</th>\n",
|
| 101 |
+
" <th>day</th>\n",
|
| 102 |
+
" <th>timestamp</th>\n",
|
| 103 |
+
" <th>demand</th>\n",
|
| 104 |
+
" </tr>\n",
|
| 105 |
+
" </thead>\n",
|
| 106 |
+
" <tbody>\n",
|
| 107 |
+
" <tr>\n",
|
| 108 |
+
" <th>0</th>\n",
|
| 109 |
+
" <td>qp03wc</td>\n",
|
| 110 |
+
" <td>18</td>\n",
|
| 111 |
+
" <td>20:0</td>\n",
|
| 112 |
+
" <td>0.020072</td>\n",
|
| 113 |
+
" </tr>\n",
|
| 114 |
+
" <tr>\n",
|
| 115 |
+
" <th>1</th>\n",
|
| 116 |
+
" <td>qp03pn</td>\n",
|
| 117 |
+
" <td>10</td>\n",
|
| 118 |
+
" <td>14:30</td>\n",
|
| 119 |
+
" <td>0.024721</td>\n",
|
| 120 |
+
" </tr>\n",
|
| 121 |
+
" <tr>\n",
|
| 122 |
+
" <th>2</th>\n",
|
| 123 |
+
" <td>qp09sw</td>\n",
|
| 124 |
+
" <td>9</td>\n",
|
| 125 |
+
" <td>6:15</td>\n",
|
| 126 |
+
" <td>0.102821</td>\n",
|
| 127 |
+
" </tr>\n",
|
| 128 |
+
" <tr>\n",
|
| 129 |
+
" <th>3</th>\n",
|
| 130 |
+
" <td>qp0991</td>\n",
|
| 131 |
+
" <td>32</td>\n",
|
| 132 |
+
" <td>5:0</td>\n",
|
| 133 |
+
" <td>0.088755</td>\n",
|
| 134 |
+
" </tr>\n",
|
| 135 |
+
" <tr>\n",
|
| 136 |
+
" <th>4</th>\n",
|
| 137 |
+
" <td>qp090q</td>\n",
|
| 138 |
+
" <td>15</td>\n",
|
| 139 |
+
" <td>4:0</td>\n",
|
| 140 |
+
" <td>0.074468</td>\n",
|
| 141 |
+
" </tr>\n",
|
| 142 |
+
" </tbody>\n",
|
| 143 |
+
"</table>\n",
|
| 144 |
+
"</div>"
|
| 145 |
+
],
|
| 146 |
+
"text/plain": [
|
| 147 |
+
" geohash6 day timestamp demand\n",
|
| 148 |
+
"0 qp03wc 18 20:0 0.020072\n",
|
| 149 |
+
"1 qp03pn 10 14:30 0.024721\n",
|
| 150 |
+
"2 qp09sw 9 6:15 0.102821\n",
|
| 151 |
+
"3 qp0991 32 5:0 0.088755\n",
|
| 152 |
+
"4 qp090q 15 4:0 0.074468"
|
| 153 |
+
]
|
| 154 |
+
},
|
| 155 |
+
"execution_count": 2,
|
| 156 |
+
"metadata": {},
|
| 157 |
+
"output_type": "execute_result"
|
| 158 |
+
}
|
| 159 |
+
],
|
| 160 |
+
"source": [
|
| 161 |
+
"import matplotlib.pyplot as plt\n",
|
| 162 |
+
"%matplotlib inline\n",
|
| 163 |
+
"import seaborn as sns\n",
|
| 164 |
+
"\n",
|
| 165 |
+
"df_train = pd.read_csv('../input/training.csv')\n",
|
| 166 |
+
"df_train.head()"
|
| 167 |
+
]
|
| 168 |
+
},
|
| 169 |
+
{
|
| 170 |
+
"cell_type": "markdown",
|
| 171 |
+
"metadata": {},
|
| 172 |
+
"source": [
|
| 173 |
+
"Size of training data:"
|
| 174 |
+
]
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"cell_type": "code",
|
| 178 |
+
"execution_count": 3,
|
| 179 |
+
"metadata": {},
|
| 180 |
+
"outputs": [
|
| 181 |
+
{
|
| 182 |
+
"data": {
|
| 183 |
+
"text/plain": [
|
| 184 |
+
"(4206321, 4)"
|
| 185 |
+
]
|
| 186 |
+
},
|
| 187 |
+
"execution_count": 3,
|
| 188 |
+
"metadata": {},
|
| 189 |
+
"output_type": "execute_result"
|
| 190 |
+
}
|
| 191 |
+
],
|
| 192 |
+
"source": [
|
| 193 |
+
"df_train.shape"
|
| 194 |
+
]
|
| 195 |
+
},
|
| 196 |
+
{
|
| 197 |
+
"cell_type": "markdown",
|
| 198 |
+
"metadata": {},
|
| 199 |
+
"source": [
|
| 200 |
+
"1329 unique locations in the data"
|
| 201 |
+
]
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
"cell_type": "code",
|
| 205 |
+
"execution_count": 4,
|
| 206 |
+
"metadata": {},
|
| 207 |
+
"outputs": [
|
| 208 |
+
{
|
| 209 |
+
"data": {
|
| 210 |
+
"text/plain": [
|
| 211 |
+
"1329"
|
| 212 |
+
]
|
| 213 |
+
},
|
| 214 |
+
"execution_count": 4,
|
| 215 |
+
"metadata": {},
|
| 216 |
+
"output_type": "execute_result"
|
| 217 |
+
}
|
| 218 |
+
],
|
| 219 |
+
"source": [
|
| 220 |
+
"len(df_train.geohash6.unique())"
|
| 221 |
+
]
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"cell_type": "markdown",
|
| 225 |
+
"metadata": {},
|
| 226 |
+
"source": [
|
| 227 |
+
"Convert timestamp into hours and mininutes:"
|
| 228 |
+
]
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"cell_type": "code",
|
| 232 |
+
"execution_count": 5,
|
| 233 |
+
"metadata": {},
|
| 234 |
+
"outputs": [
|
| 235 |
+
{
|
| 236 |
+
"data": {
|
| 237 |
+
"text/html": [
|
| 238 |
+
"<div>\n",
|
| 239 |
+
"<style scoped>\n",
|
| 240 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 241 |
+
" vertical-align: middle;\n",
|
| 242 |
+
" }\n",
|
| 243 |
+
"\n",
|
| 244 |
+
" .dataframe tbody tr th {\n",
|
| 245 |
+
" vertical-align: top;\n",
|
| 246 |
+
" }\n",
|
| 247 |
+
"\n",
|
| 248 |
+
" .dataframe thead th {\n",
|
| 249 |
+
" text-align: right;\n",
|
| 250 |
+
" }\n",
|
| 251 |
+
"</style>\n",
|
| 252 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 253 |
+
" <thead>\n",
|
| 254 |
+
" <tr style=\"text-align: right;\">\n",
|
| 255 |
+
" <th></th>\n",
|
| 256 |
+
" <th>geohash6</th>\n",
|
| 257 |
+
" <th>day</th>\n",
|
| 258 |
+
" <th>timestamp</th>\n",
|
| 259 |
+
" <th>demand</th>\n",
|
| 260 |
+
" <th>hours</th>\n",
|
| 261 |
+
" <th>mins</th>\n",
|
| 262 |
+
" </tr>\n",
|
| 263 |
+
" </thead>\n",
|
| 264 |
+
" <tbody>\n",
|
| 265 |
+
" <tr>\n",
|
| 266 |
+
" <th>0</th>\n",
|
| 267 |
+
" <td>qp03wc</td>\n",
|
| 268 |
+
" <td>18</td>\n",
|
| 269 |
+
" <td>20:0</td>\n",
|
| 270 |
+
" <td>0.020072</td>\n",
|
| 271 |
+
" <td>20</td>\n",
|
| 272 |
+
" <td>0</td>\n",
|
| 273 |
+
" </tr>\n",
|
| 274 |
+
" <tr>\n",
|
| 275 |
+
" <th>1</th>\n",
|
| 276 |
+
" <td>qp03pn</td>\n",
|
| 277 |
+
" <td>10</td>\n",
|
| 278 |
+
" <td>14:30</td>\n",
|
| 279 |
+
" <td>0.024721</td>\n",
|
| 280 |
+
" <td>14</td>\n",
|
| 281 |
+
" <td>30</td>\n",
|
| 282 |
+
" </tr>\n",
|
| 283 |
+
" <tr>\n",
|
| 284 |
+
" <th>2</th>\n",
|
| 285 |
+
" <td>qp09sw</td>\n",
|
| 286 |
+
" <td>9</td>\n",
|
| 287 |
+
" <td>6:15</td>\n",
|
| 288 |
+
" <td>0.102821</td>\n",
|
| 289 |
+
" <td>6</td>\n",
|
| 290 |
+
" <td>15</td>\n",
|
| 291 |
+
" </tr>\n",
|
| 292 |
+
" <tr>\n",
|
| 293 |
+
" <th>3</th>\n",
|
| 294 |
+
" <td>qp0991</td>\n",
|
| 295 |
+
" <td>32</td>\n",
|
| 296 |
+
" <td>5:0</td>\n",
|
| 297 |
+
" <td>0.088755</td>\n",
|
| 298 |
+
" <td>5</td>\n",
|
| 299 |
+
" <td>0</td>\n",
|
| 300 |
+
" </tr>\n",
|
| 301 |
+
" <tr>\n",
|
| 302 |
+
" <th>4</th>\n",
|
| 303 |
+
" <td>qp090q</td>\n",
|
| 304 |
+
" <td>15</td>\n",
|
| 305 |
+
" <td>4:0</td>\n",
|
| 306 |
+
" <td>0.074468</td>\n",
|
| 307 |
+
" <td>4</td>\n",
|
| 308 |
+
" <td>0</td>\n",
|
| 309 |
+
" </tr>\n",
|
| 310 |
+
" </tbody>\n",
|
| 311 |
+
"</table>\n",
|
| 312 |
+
"</div>"
|
| 313 |
+
],
|
| 314 |
+
"text/plain": [
|
| 315 |
+
" geohash6 day timestamp demand hours mins\n",
|
| 316 |
+
"0 qp03wc 18 20:0 0.020072 20 0\n",
|
| 317 |
+
"1 qp03pn 10 14:30 0.024721 14 30\n",
|
| 318 |
+
"2 qp09sw 9 6:15 0.102821 6 15\n",
|
| 319 |
+
"3 qp0991 32 5:0 0.088755 5 0\n",
|
| 320 |
+
"4 qp090q 15 4:0 0.074468 4 0"
|
| 321 |
+
]
|
| 322 |
+
},
|
| 323 |
+
"execution_count": 5,
|
| 324 |
+
"metadata": {},
|
| 325 |
+
"output_type": "execute_result"
|
| 326 |
+
}
|
| 327 |
+
],
|
| 328 |
+
"source": [
|
| 329 |
+
"df_train['hours'] = df_train['timestamp'].map(lambda x: int(x.split(':')[0]))\n",
|
| 330 |
+
"df_train['mins'] = df_train['timestamp'].map(lambda x: int(x.split(':')[1]))\n",
|
| 331 |
+
"df_train.head()"
|
| 332 |
+
]
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"cell_type": "markdown",
|
| 336 |
+
"metadata": {},
|
| 337 |
+
"source": [
|
| 338 |
+
"Convert day, hours, mins into a single feature **\"time\"**:"
|
| 339 |
+
]
|
| 340 |
+
},
|
| 341 |
+
{
|
| 342 |
+
"cell_type": "code",
|
| 343 |
+
"execution_count": 6,
|
| 344 |
+
"metadata": {},
|
| 345 |
+
"outputs": [
|
| 346 |
+
{
|
| 347 |
+
"data": {
|
| 348 |
+
"text/html": [
|
| 349 |
+
"<div>\n",
|
| 350 |
+
"<style scoped>\n",
|
| 351 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 352 |
+
" vertical-align: middle;\n",
|
| 353 |
+
" }\n",
|
| 354 |
+
"\n",
|
| 355 |
+
" .dataframe tbody tr th {\n",
|
| 356 |
+
" vertical-align: top;\n",
|
| 357 |
+
" }\n",
|
| 358 |
+
"\n",
|
| 359 |
+
" .dataframe thead th {\n",
|
| 360 |
+
" text-align: right;\n",
|
| 361 |
+
" }\n",
|
| 362 |
+
"</style>\n",
|
| 363 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 364 |
+
" <thead>\n",
|
| 365 |
+
" <tr style=\"text-align: right;\">\n",
|
| 366 |
+
" <th></th>\n",
|
| 367 |
+
" <th>geohash6</th>\n",
|
| 368 |
+
" <th>day</th>\n",
|
| 369 |
+
" <th>timestamp</th>\n",
|
| 370 |
+
" <th>demand</th>\n",
|
| 371 |
+
" <th>hours</th>\n",
|
| 372 |
+
" <th>mins</th>\n",
|
| 373 |
+
" <th>time</th>\n",
|
| 374 |
+
" </tr>\n",
|
| 375 |
+
" </thead>\n",
|
| 376 |
+
" <tbody>\n",
|
| 377 |
+
" <tr>\n",
|
| 378 |
+
" <th>0</th>\n",
|
| 379 |
+
" <td>qp03wc</td>\n",
|
| 380 |
+
" <td>18</td>\n",
|
| 381 |
+
" <td>20:0</td>\n",
|
| 382 |
+
" <td>0.020072</td>\n",
|
| 383 |
+
" <td>20</td>\n",
|
| 384 |
+
" <td>0</td>\n",
|
| 385 |
+
" <td>25680</td>\n",
|
| 386 |
+
" </tr>\n",
|
| 387 |
+
" <tr>\n",
|
| 388 |
+
" <th>1</th>\n",
|
| 389 |
+
" <td>qp03pn</td>\n",
|
| 390 |
+
" <td>10</td>\n",
|
| 391 |
+
" <td>14:30</td>\n",
|
| 392 |
+
" <td>0.024721</td>\n",
|
| 393 |
+
" <td>14</td>\n",
|
| 394 |
+
" <td>30</td>\n",
|
| 395 |
+
" <td>13830</td>\n",
|
| 396 |
+
" </tr>\n",
|
| 397 |
+
" <tr>\n",
|
| 398 |
+
" <th>2</th>\n",
|
| 399 |
+
" <td>qp09sw</td>\n",
|
| 400 |
+
" <td>9</td>\n",
|
| 401 |
+
" <td>6:15</td>\n",
|
| 402 |
+
" <td>0.102821</td>\n",
|
| 403 |
+
" <td>6</td>\n",
|
| 404 |
+
" <td>15</td>\n",
|
| 405 |
+
" <td>11895</td>\n",
|
| 406 |
+
" </tr>\n",
|
| 407 |
+
" <tr>\n",
|
| 408 |
+
" <th>3</th>\n",
|
| 409 |
+
" <td>qp0991</td>\n",
|
| 410 |
+
" <td>32</td>\n",
|
| 411 |
+
" <td>5:0</td>\n",
|
| 412 |
+
" <td>0.088755</td>\n",
|
| 413 |
+
" <td>5</td>\n",
|
| 414 |
+
" <td>0</td>\n",
|
| 415 |
+
" <td>44940</td>\n",
|
| 416 |
+
" </tr>\n",
|
| 417 |
+
" <tr>\n",
|
| 418 |
+
" <th>4</th>\n",
|
| 419 |
+
" <td>qp090q</td>\n",
|
| 420 |
+
" <td>15</td>\n",
|
| 421 |
+
" <td>4:0</td>\n",
|
| 422 |
+
" <td>0.074468</td>\n",
|
| 423 |
+
" <td>4</td>\n",
|
| 424 |
+
" <td>0</td>\n",
|
| 425 |
+
" <td>20400</td>\n",
|
| 426 |
+
" </tr>\n",
|
| 427 |
+
" </tbody>\n",
|
| 428 |
+
"</table>\n",
|
| 429 |
+
"</div>"
|
| 430 |
+
],
|
| 431 |
+
"text/plain": [
|
| 432 |
+
" geohash6 day timestamp demand hours mins time\n",
|
| 433 |
+
"0 qp03wc 18 20:0 0.020072 20 0 25680\n",
|
| 434 |
+
"1 qp03pn 10 14:30 0.024721 14 30 13830\n",
|
| 435 |
+
"2 qp09sw 9 6:15 0.102821 6 15 11895\n",
|
| 436 |
+
"3 qp0991 32 5:0 0.088755 5 0 44940\n",
|
| 437 |
+
"4 qp090q 15 4:0 0.074468 4 0 20400"
|
| 438 |
+
]
|
| 439 |
+
},
|
| 440 |
+
"execution_count": 6,
|
| 441 |
+
"metadata": {},
|
| 442 |
+
"output_type": "execute_result"
|
| 443 |
+
}
|
| 444 |
+
],
|
| 445 |
+
"source": [
|
| 446 |
+
"df_train['time'] = 24*60*(df_train['day']-1) + 60*df_train['hours'] + df_train['mins']\n",
|
| 447 |
+
"df_train.head()"
|
| 448 |
+
]
|
| 449 |
+
},
|
| 450 |
+
{
|
| 451 |
+
"cell_type": "markdown",
|
| 452 |
+
"metadata": {},
|
| 453 |
+
"source": [
|
| 454 |
+
"Convert geohash6 into latitude and longtitude:"
|
| 455 |
+
]
|
| 456 |
+
},
|
| 457 |
+
{
|
| 458 |
+
"cell_type": "code",
|
| 459 |
+
"execution_count": 7,
|
| 460 |
+
"metadata": {},
|
| 461 |
+
"outputs": [
|
| 462 |
+
{
|
| 463 |
+
"data": {
|
| 464 |
+
"text/html": [
|
| 465 |
+
"<div>\n",
|
| 466 |
+
"<style scoped>\n",
|
| 467 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 468 |
+
" vertical-align: middle;\n",
|
| 469 |
+
" }\n",
|
| 470 |
+
"\n",
|
| 471 |
+
" .dataframe tbody tr th {\n",
|
| 472 |
+
" vertical-align: top;\n",
|
| 473 |
+
" }\n",
|
| 474 |
+
"\n",
|
| 475 |
+
" .dataframe thead th {\n",
|
| 476 |
+
" text-align: right;\n",
|
| 477 |
+
" }\n",
|
| 478 |
+
"</style>\n",
|
| 479 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 480 |
+
" <thead>\n",
|
| 481 |
+
" <tr style=\"text-align: right;\">\n",
|
| 482 |
+
" <th></th>\n",
|
| 483 |
+
" <th>geohash6</th>\n",
|
| 484 |
+
" <th>day</th>\n",
|
| 485 |
+
" <th>timestamp</th>\n",
|
| 486 |
+
" <th>demand</th>\n",
|
| 487 |
+
" <th>hours</th>\n",
|
| 488 |
+
" <th>mins</th>\n",
|
| 489 |
+
" <th>time</th>\n",
|
| 490 |
+
" <th>Latitude</th>\n",
|
| 491 |
+
" <th>Longitude</th>\n",
|
| 492 |
+
" </tr>\n",
|
| 493 |
+
" </thead>\n",
|
| 494 |
+
" <tbody>\n",
|
| 495 |
+
" <tr>\n",
|
| 496 |
+
" <th>0</th>\n",
|
| 497 |
+
" <td>qp02zd</td>\n",
|
| 498 |
+
" <td>1</td>\n",
|
| 499 |
+
" <td>0:0</td>\n",
|
| 500 |
+
" <td>0.022396</td>\n",
|
| 501 |
+
" <td>0</td>\n",
|
| 502 |
+
" <td>0</td>\n",
|
| 503 |
+
" <td>0</td>\n",
|
| 504 |
+
" <td>-5.479431</td>\n",
|
| 505 |
+
" <td>90.686646</td>\n",
|
| 506 |
+
" </tr>\n",
|
| 507 |
+
" <tr>\n",
|
| 508 |
+
" <th>1</th>\n",
|
| 509 |
+
" <td>qp02zu</td>\n",
|
| 510 |
+
" <td>1</td>\n",
|
| 511 |
+
" <td>0:0</td>\n",
|
| 512 |
+
" <td>0.001831</td>\n",
|
| 513 |
+
" <td>0</td>\n",
|
| 514 |
+
" <td>0</td>\n",
|
| 515 |
+
" <td>0</td>\n",
|
| 516 |
+
" <td>-5.468445</td>\n",
|
| 517 |
+
" <td>90.697632</td>\n",
|
| 518 |
+
" </tr>\n",
|
| 519 |
+
" <tr>\n",
|
| 520 |
+
" <th>2</th>\n",
|
| 521 |
+
" <td>qp02zt</td>\n",
|
| 522 |
+
" <td>1</td>\n",
|
| 523 |
+
" <td>0:0</td>\n",
|
| 524 |
+
" <td>0.001112</td>\n",
|
| 525 |
+
" <td>0</td>\n",
|
| 526 |
+
" <td>0</td>\n",
|
| 527 |
+
" <td>0</td>\n",
|
| 528 |
+
" <td>-5.462952</td>\n",
|
| 529 |
+
" <td>90.686646</td>\n",
|
| 530 |
+
" </tr>\n",
|
| 531 |
+
" <tr>\n",
|
| 532 |
+
" <th>3</th>\n",
|
| 533 |
+
" <td>qp02zv</td>\n",
|
| 534 |
+
" <td>1</td>\n",
|
| 535 |
+
" <td>0:0</td>\n",
|
| 536 |
+
" <td>0.006886</td>\n",
|
| 537 |
+
" <td>0</td>\n",
|
| 538 |
+
" <td>0</td>\n",
|
| 539 |
+
" <td>0</td>\n",
|
| 540 |
+
" <td>-5.462952</td>\n",
|
| 541 |
+
" <td>90.697632</td>\n",
|
| 542 |
+
" </tr>\n",
|
| 543 |
+
" <tr>\n",
|
| 544 |
+
" <th>4</th>\n",
|
| 545 |
+
" <td>qp08bj</td>\n",
|
| 546 |
+
" <td>1</td>\n",
|
| 547 |
+
" <td>0:0</td>\n",
|
| 548 |
+
" <td>0.066376</td>\n",
|
| 549 |
+
" <td>0</td>\n",
|
| 550 |
+
" <td>0</td>\n",
|
| 551 |
+
" <td>0</td>\n",
|
| 552 |
+
" <td>-5.462952</td>\n",
|
| 553 |
+
" <td>90.708618</td>\n",
|
| 554 |
+
" </tr>\n",
|
| 555 |
+
" </tbody>\n",
|
| 556 |
+
"</table>\n",
|
| 557 |
+
"</div>"
|
| 558 |
+
],
|
| 559 |
+
"text/plain": [
|
| 560 |
+
" geohash6 day timestamp demand ... mins time Latitude Longitude\n",
|
| 561 |
+
"0 qp02zd 1 0:0 0.022396 ... 0 0 -5.479431 90.686646\n",
|
| 562 |
+
"1 qp02zu 1 0:0 0.001831 ... 0 0 -5.468445 90.697632\n",
|
| 563 |
+
"2 qp02zt 1 0:0 0.001112 ... 0 0 -5.462952 90.686646\n",
|
| 564 |
+
"3 qp02zv 1 0:0 0.006886 ... 0 0 -5.462952 90.697632\n",
|
| 565 |
+
"4 qp08bj 1 0:0 0.066376 ... 0 0 -5.462952 90.708618\n",
|
| 566 |
+
"\n",
|
| 567 |
+
"[5 rows x 9 columns]"
|
| 568 |
+
]
|
| 569 |
+
},
|
| 570 |
+
"execution_count": 7,
|
| 571 |
+
"metadata": {},
|
| 572 |
+
"output_type": "execute_result"
|
| 573 |
+
}
|
| 574 |
+
],
|
| 575 |
+
"source": [
|
| 576 |
+
"import Geohash\n",
|
| 577 |
+
"df_train['Latitude'] = df_train.geohash6.map(lambda x: float(Geohash.decode_exactly(x)[0]))\n",
|
| 578 |
+
"df_train['Longitude'] = df_train.geohash6.map(lambda x: float(Geohash.decode_exactly(x)[1]))\n",
|
| 579 |
+
"df_train = df_train.sort_values(by=['time','Latitude','Longitude'], ascending=True)\n",
|
| 580 |
+
"df_train = df_train.reset_index().drop('index',axis=1)\n",
|
| 581 |
+
"df_train.head()"
|
| 582 |
+
]
|
| 583 |
+
},
|
| 584 |
+
{
|
| 585 |
+
"cell_type": "markdown",
|
| 586 |
+
"metadata": {},
|
| 587 |
+
"source": [
|
| 588 |
+
"Not all locations appear in all time slots"
|
| 589 |
+
]
|
| 590 |
+
},
|
| 591 |
+
{
|
| 592 |
+
"cell_type": "code",
|
| 593 |
+
"execution_count": 8,
|
| 594 |
+
"metadata": {},
|
| 595 |
+
"outputs": [
|
| 596 |
+
{
|
| 597 |
+
"data": {
|
| 598 |
+
"text/html": [
|
| 599 |
+
"<div>\n",
|
| 600 |
+
"<style scoped>\n",
|
| 601 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 602 |
+
" vertical-align: middle;\n",
|
| 603 |
+
" }\n",
|
| 604 |
+
"\n",
|
| 605 |
+
" .dataframe tbody tr th {\n",
|
| 606 |
+
" vertical-align: top;\n",
|
| 607 |
+
" }\n",
|
| 608 |
+
"\n",
|
| 609 |
+
" .dataframe thead th {\n",
|
| 610 |
+
" text-align: right;\n",
|
| 611 |
+
" }\n",
|
| 612 |
+
"</style>\n",
|
| 613 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 614 |
+
" <thead>\n",
|
| 615 |
+
" <tr style=\"text-align: right;\">\n",
|
| 616 |
+
" <th></th>\n",
|
| 617 |
+
" <th>demand</th>\n",
|
| 618 |
+
" </tr>\n",
|
| 619 |
+
" <tr>\n",
|
| 620 |
+
" <th>geohash6</th>\n",
|
| 621 |
+
" <th></th>\n",
|
| 622 |
+
" </tr>\n",
|
| 623 |
+
" </thead>\n",
|
| 624 |
+
" <tbody>\n",
|
| 625 |
+
" <tr>\n",
|
| 626 |
+
" <th>qp02yc</th>\n",
|
| 627 |
+
" <td>577</td>\n",
|
| 628 |
+
" </tr>\n",
|
| 629 |
+
" <tr>\n",
|
| 630 |
+
" <th>qp02yf</th>\n",
|
| 631 |
+
" <td>89</td>\n",
|
| 632 |
+
" </tr>\n",
|
| 633 |
+
" <tr>\n",
|
| 634 |
+
" <th>qp02yu</th>\n",
|
| 635 |
+
" <td>2</td>\n",
|
| 636 |
+
" </tr>\n",
|
| 637 |
+
" <tr>\n",
|
| 638 |
+
" <th>qp02yv</th>\n",
|
| 639 |
+
" <td>7</td>\n",
|
| 640 |
+
" </tr>\n",
|
| 641 |
+
" <tr>\n",
|
| 642 |
+
" <th>qp02yy</th>\n",
|
| 643 |
+
" <td>106</td>\n",
|
| 644 |
+
" </tr>\n",
|
| 645 |
+
" <tr>\n",
|
| 646 |
+
" <th>qp02yz</th>\n",
|
| 647 |
+
" <td>879</td>\n",
|
| 648 |
+
" </tr>\n",
|
| 649 |
+
" <tr>\n",
|
| 650 |
+
" <th>qp02z1</th>\n",
|
| 651 |
+
" <td>1153</td>\n",
|
| 652 |
+
" </tr>\n",
|
| 653 |
+
" <tr>\n",
|
| 654 |
+
" <th>qp02z3</th>\n",
|
| 655 |
+
" <td>567</td>\n",
|
| 656 |
+
" </tr>\n",
|
| 657 |
+
" <tr>\n",
|
| 658 |
+
" <th>qp02z4</th>\n",
|
| 659 |
+
" <td>448</td>\n",
|
| 660 |
+
" </tr>\n",
|
| 661 |
+
" <tr>\n",
|
| 662 |
+
" <th>qp02z5</th>\n",
|
| 663 |
+
" <td>1491</td>\n",
|
| 664 |
+
" </tr>\n",
|
| 665 |
+
" </tbody>\n",
|
| 666 |
+
"</table>\n",
|
| 667 |
+
"</div>"
|
| 668 |
+
],
|
| 669 |
+
"text/plain": [
|
| 670 |
+
" demand\n",
|
| 671 |
+
"geohash6 \n",
|
| 672 |
+
"qp02yc 577\n",
|
| 673 |
+
"qp02yf 89\n",
|
| 674 |
+
"qp02yu 2\n",
|
| 675 |
+
"qp02yv 7\n",
|
| 676 |
+
"qp02yy 106\n",
|
| 677 |
+
"qp02yz 879\n",
|
| 678 |
+
"qp02z1 1153\n",
|
| 679 |
+
"qp02z3 567\n",
|
| 680 |
+
"qp02z4 448\n",
|
| 681 |
+
"qp02z5 1491"
|
| 682 |
+
]
|
| 683 |
+
},
|
| 684 |
+
"execution_count": 8,
|
| 685 |
+
"metadata": {},
|
| 686 |
+
"output_type": "execute_result"
|
| 687 |
+
}
|
| 688 |
+
],
|
| 689 |
+
"source": [
|
| 690 |
+
"df_train[['geohash6','demand']].groupby('geohash6').count().head(10)"
|
| 691 |
+
]
|
| 692 |
+
},
|
| 693 |
+
{
|
| 694 |
+
"cell_type": "markdown",
|
| 695 |
+
"metadata": {},
|
| 696 |
+
"source": [
|
| 697 |
+
"As the training set is a huge dataset with more than 4 million data, I will only use the last 14 days' data, out of which the last five timestamps are used for testing purpose and the rest is for training purpose."
|
| 698 |
+
]
|
| 699 |
+
},
|
| 700 |
+
{
|
| 701 |
+
"cell_type": "code",
|
| 702 |
+
"execution_count": 9,
|
| 703 |
+
"metadata": {},
|
| 704 |
+
"outputs": [],
|
| 705 |
+
"source": [
|
| 706 |
+
"max_day = df_train.day.max()\n",
|
| 707 |
+
"max_time = df_train.time.max()\n",
|
| 708 |
+
"train_start = df_train[df_train.day==61-13].index[0]\n",
|
| 709 |
+
"test_start = df_train[df_train.time==max_time-15*4].index[0]\n",
|
| 710 |
+
"\n",
|
| 711 |
+
"Xtrain = df_train[['time', 'Latitude','Longitude']].iloc[train_start:test_start,:]\n",
|
| 712 |
+
"Xtest = df_train[['time', 'Latitude','Longitude']].iloc[test_start:,:]\n",
|
| 713 |
+
"\n",
|
| 714 |
+
"ytrain = df_train.demand.iloc[train_start:test_start]\n",
|
| 715 |
+
"ytest = df_train.demand.iloc[test_start:]"
|
| 716 |
+
]
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"cell_type": "code",
|
| 720 |
+
"execution_count": 10,
|
| 721 |
+
"metadata": {},
|
| 722 |
+
"outputs": [
|
| 723 |
+
{
|
| 724 |
+
"data": {
|
| 725 |
+
"text/plain": [
|
| 726 |
+
"((990189, 3), (2640, 3), (990189,), (2640,))"
|
| 727 |
+
]
|
| 728 |
+
},
|
| 729 |
+
"execution_count": 10,
|
| 730 |
+
"metadata": {},
|
| 731 |
+
"output_type": "execute_result"
|
| 732 |
+
}
|
| 733 |
+
],
|
| 734 |
+
"source": [
|
| 735 |
+
"Xtrain.shape, Xtest.shape, ytrain.shape, ytest.shape"
|
| 736 |
+
]
|
| 737 |
+
},
|
| 738 |
+
{
|
| 739 |
+
"cell_type": "markdown",
|
| 740 |
+
"metadata": {},
|
| 741 |
+
"source": [
|
| 742 |
+
"## Part 2 - Model Selection"
|
| 743 |
+
]
|
| 744 |
+
},
|
| 745 |
+
{
|
| 746 |
+
"cell_type": "markdown",
|
| 747 |
+
"metadata": {},
|
| 748 |
+
"source": [
|
| 749 |
+
"### Part 2.1 - RandomForestRegressor"
|
| 750 |
+
]
|
| 751 |
+
},
|
| 752 |
+
{
|
| 753 |
+
"cell_type": "code",
|
| 754 |
+
"execution_count": 11,
|
| 755 |
+
"metadata": {},
|
| 756 |
+
"outputs": [
|
| 757 |
+
{
|
| 758 |
+
"name": "stdout",
|
| 759 |
+
"output_type": "stream",
|
| 760 |
+
"text": [
|
| 761 |
+
"RMSE: 0.03347819383369924\n"
|
| 762 |
+
]
|
| 763 |
+
}
|
| 764 |
+
],
|
| 765 |
+
"source": [
|
| 766 |
+
"from sklearn.ensemble import RandomForestRegressor\n",
|
| 767 |
+
"from sklearn.metrics import mean_squared_error\n",
|
| 768 |
+
"\n",
|
| 769 |
+
"model = RandomForestRegressor(n_estimators=30, max_depth=40)\n",
|
| 770 |
+
"model.fit(Xtrain, ytrain)\n",
|
| 771 |
+
"ytest_pred = model.predict(Xtest)\n",
|
| 772 |
+
"rmse = np.sqrt(mean_squared_error(ytest, ytest_pred))\n",
|
| 773 |
+
"print('RMSE:',rmse)"
|
| 774 |
+
]
|
| 775 |
+
},
|
| 776 |
+
{
|
| 777 |
+
"cell_type": "markdown",
|
| 778 |
+
"metadata": {},
|
| 779 |
+
"source": [
|
| 780 |
+
"### Part 2.2 - XGBRegressor"
|
| 781 |
+
]
|
| 782 |
+
},
|
| 783 |
+
{
|
| 784 |
+
"cell_type": "code",
|
| 785 |
+
"execution_count": 12,
|
| 786 |
+
"metadata": {},
|
| 787 |
+
"outputs": [
|
| 788 |
+
{
|
| 789 |
+
"name": "stderr",
|
| 790 |
+
"output_type": "stream",
|
| 791 |
+
"text": [
|
| 792 |
+
"/opt/conda/lib/python3.6/site-packages/xgboost/core.py:587: FutureWarning: Series.base is deprecated and will be removed in a future version\n",
|
| 793 |
+
" if getattr(data, 'base', None) is not None and \\\n",
|
| 794 |
+
"/opt/conda/lib/python3.6/site-packages/xgboost/core.py:588: FutureWarning: Series.base is deprecated and will be removed in a future version\n",
|
| 795 |
+
" data.base is not None and isinstance(data, np.ndarray) \\\n"
|
| 796 |
+
]
|
| 797 |
+
},
|
| 798 |
+
{
|
| 799 |
+
"name": "stdout",
|
| 800 |
+
"output_type": "stream",
|
| 801 |
+
"text": [
|
| 802 |
+
"RMSE: 0.032064894772248616\n"
|
| 803 |
+
]
|
| 804 |
+
}
|
| 805 |
+
],
|
| 806 |
+
"source": [
|
| 807 |
+
"from xgboost import XGBRegressor\n",
|
| 808 |
+
"\n",
|
| 809 |
+
"model = XGBRegressor(n_estimators=500, learning_rate=0.05, max_depth=35)\n",
|
| 810 |
+
"model.fit(Xtrain, ytrain)\n",
|
| 811 |
+
"ytest_pred = model.predict(Xtest)\n",
|
| 812 |
+
"rmse = np.sqrt(mean_squared_error(ytest, ytest_pred))\n",
|
| 813 |
+
"print('RMSE:',rmse)"
|
| 814 |
+
]
|
| 815 |
+
},
|
| 816 |
+
{
|
| 817 |
+
"cell_type": "markdown",
|
| 818 |
+
"metadata": {},
|
| 819 |
+
"source": [
|
| 820 |
+
"#### From above output, XGBRegressor produces a smaller RMSE than RandomForestRegressor. Hence XGBRegressor will be used. \n",
|
| 821 |
+
"#### All the hyperparameters above have been refined.[](http://)"
|
| 822 |
+
]
|
| 823 |
+
},
|
| 824 |
+
{
|
| 825 |
+
"cell_type": "markdown",
|
| 826 |
+
"metadata": {},
|
| 827 |
+
"source": [
|
| 828 |
+
"Define a function to convert time into day, hour, minute and timestamp:"
|
| 829 |
+
]
|
| 830 |
+
},
|
| 831 |
+
{
|
| 832 |
+
"cell_type": "code",
|
| 833 |
+
"execution_count": 13,
|
| 834 |
+
"metadata": {},
|
| 835 |
+
"outputs": [],
|
| 836 |
+
"source": [
|
| 837 |
+
"def convert_time(time):\n",
|
| 838 |
+
" day = int(time/(24*60)) + 1\n",
|
| 839 |
+
" hour = int((time-(day-1)*24*60)/60)\n",
|
| 840 |
+
" minute = time-(day-1)*24*60-hour*60\n",
|
| 841 |
+
" timestamp = ':'.join((str(hour),str(minute)))\n",
|
| 842 |
+
" return (day, hour, minute, timestamp)"
|
| 843 |
+
]
|
| 844 |
+
},
|
| 845 |
+
{
|
| 846 |
+
"cell_type": "markdown",
|
| 847 |
+
"metadata": {},
|
| 848 |
+
"source": [
|
| 849 |
+
"## Part 3 - Define a function to predict demands of T+1, ..., T+5 using known data till T "
|
| 850 |
+
]
|
| 851 |
+
},
|
| 852 |
+
{
|
| 853 |
+
"cell_type": "code",
|
| 854 |
+
"execution_count": 14,
|
| 855 |
+
"metadata": {},
|
| 856 |
+
"outputs": [],
|
| 857 |
+
"source": [
|
| 858 |
+
"def predict5ts(link, n_estimators=500, learning_rate=0.05, max_depth=35):\n",
|
| 859 |
+
" df = pd.read_csv(link)\n",
|
| 860 |
+
" df['hours'] = df['timestamp'].map(lambda x: int(x.split(':')[0]))\n",
|
| 861 |
+
" df['mins'] = df['timestamp'].map(lambda x: int(x.split(':')[1]))\n",
|
| 862 |
+
" df['time'] = 24*60*(df['day']-1) + 60*df['hours'] + df['mins']\n",
|
| 863 |
+
" \n",
|
| 864 |
+
" import Geohash\n",
|
| 865 |
+
" df['Latitude'] = df.geohash6.map(lambda x: float(Geohash.decode_exactly(x)[0]))\n",
|
| 866 |
+
" df['Longitude'] = df.geohash6.map(lambda x: float(Geohash.decode_exactly(x)[1]))\n",
|
| 867 |
+
"\n",
|
| 868 |
+
" df = df.sort_values(by=['time','Latitude','Longitude'], ascending=True)\n",
|
| 869 |
+
" df = df.reset_index().drop('index',axis=1)\n",
|
| 870 |
+
" \n",
|
| 871 |
+
" X = df[['time', 'Latitude','Longitude']]\n",
|
| 872 |
+
" y = df.demand\n",
|
| 873 |
+
" \n",
|
| 874 |
+
" from xgboost import XGBRegressor\n",
|
| 875 |
+
" model = XGBRegressor(n_estimators=n_estimators, learning_rate=learning_rate, max_depth=max_depth)\n",
|
| 876 |
+
" model.fit(X, y)\n",
|
| 877 |
+
" \n",
|
| 878 |
+
" T = df.time.max()\n",
|
| 879 |
+
" T1 = T+15\n",
|
| 880 |
+
" T2 = T+15*2\n",
|
| 881 |
+
" T3 = T+15*3\n",
|
| 882 |
+
" T4 = T+15*4\n",
|
| 883 |
+
" T5 = T+15*5\n",
|
| 884 |
+
" \n",
|
| 885 |
+
" geohashes = df_train.geohash6.unique()\n",
|
| 886 |
+
" geohashes2 = []\n",
|
| 887 |
+
" latitudes = []\n",
|
| 888 |
+
" longitudes = []\n",
|
| 889 |
+
" times = []\n",
|
| 890 |
+
" days = []\n",
|
| 891 |
+
" timestamps = []\n",
|
| 892 |
+
"\n",
|
| 893 |
+
" for t in (T1,T2,T3,T4,T5):\n",
|
| 894 |
+
" for gh in geohashes:\n",
|
| 895 |
+
" geohashes2.append(gh)\n",
|
| 896 |
+
" latitudes.append(float(Geohash.decode_exactly(gh)[0]))\n",
|
| 897 |
+
" longitudes.append(float(Geohash.decode_exactly(gh)[1]))\n",
|
| 898 |
+
" times.append(t)\n",
|
| 899 |
+
" days.append(convert_time(t)[0])\n",
|
| 900 |
+
" timestamps.append(convert_time(t)[-1])\n",
|
| 901 |
+
"\n",
|
| 902 |
+
" df_pred = pd.DataFrame({'geohash6': geohashes2, 'day': days, 'timestamp': timestamps,\n",
|
| 903 |
+
" 'time': times, 'Latitude': latitudes, 'Longitude': longitudes})\n",
|
| 904 |
+
" Xtest = df_pred[['time', 'Latitude','Longitude']]\n",
|
| 905 |
+
" ypred = model.predict(Xtest)\n",
|
| 906 |
+
"\n",
|
| 907 |
+
" df_pred['demand'] = ypred\n",
|
| 908 |
+
" output = df_pred[['geohash6', 'day', 'timestamp', 'demand']]\n",
|
| 909 |
+
" output.to_csv('output.csv', index=False)"
|
| 910 |
+
]
|
| 911 |
+
},
|
| 912 |
+
{
|
| 913 |
+
"cell_type": "markdown",
|
| 914 |
+
"metadata": {},
|
| 915 |
+
"source": [
|
| 916 |
+
"Check if the above function works by testing a small portion of data from the training set."
|
| 917 |
+
]
|
| 918 |
+
},
|
| 919 |
+
{
|
| 920 |
+
"cell_type": "code",
|
| 921 |
+
"execution_count": 15,
|
| 922 |
+
"metadata": {},
|
| 923 |
+
"outputs": [
|
| 924 |
+
{
|
| 925 |
+
"name": "stderr",
|
| 926 |
+
"output_type": "stream",
|
| 927 |
+
"text": [
|
| 928 |
+
"/opt/conda/lib/python3.6/site-packages/xgboost/core.py:587: FutureWarning: Series.base is deprecated and will be removed in a future version\n",
|
| 929 |
+
" if getattr(data, 'base', None) is not None and \\\n",
|
| 930 |
+
"/opt/conda/lib/python3.6/site-packages/xgboost/core.py:588: FutureWarning: Series.base is deprecated and will be removed in a future version\n",
|
| 931 |
+
" data.base is not None and isinstance(data, np.ndarray) \\\n"
|
| 932 |
+
]
|
| 933 |
+
},
|
| 934 |
+
{
|
| 935 |
+
"name": "stdout",
|
| 936 |
+
"output_type": "stream",
|
| 937 |
+
"text": [
|
| 938 |
+
"(6645, 4)\n"
|
| 939 |
+
]
|
| 940 |
+
},
|
| 941 |
+
{
|
| 942 |
+
"data": {
|
| 943 |
+
"text/html": [
|
| 944 |
+
"<div>\n",
|
| 945 |
+
"<style scoped>\n",
|
| 946 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 947 |
+
" vertical-align: middle;\n",
|
| 948 |
+
" }\n",
|
| 949 |
+
"\n",
|
| 950 |
+
" .dataframe tbody tr th {\n",
|
| 951 |
+
" vertical-align: top;\n",
|
| 952 |
+
" }\n",
|
| 953 |
+
"\n",
|
| 954 |
+
" .dataframe thead th {\n",
|
| 955 |
+
" text-align: right;\n",
|
| 956 |
+
" }\n",
|
| 957 |
+
"</style>\n",
|
| 958 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 959 |
+
" <thead>\n",
|
| 960 |
+
" <tr style=\"text-align: right;\">\n",
|
| 961 |
+
" <th></th>\n",
|
| 962 |
+
" <th>geohash6</th>\n",
|
| 963 |
+
" <th>day</th>\n",
|
| 964 |
+
" <th>timestamp</th>\n",
|
| 965 |
+
" <th>demand</th>\n",
|
| 966 |
+
" </tr>\n",
|
| 967 |
+
" </thead>\n",
|
| 968 |
+
" <tbody>\n",
|
| 969 |
+
" <tr>\n",
|
| 970 |
+
" <th>0</th>\n",
|
| 971 |
+
" <td>qp02zd</td>\n",
|
| 972 |
+
" <td>62</td>\n",
|
| 973 |
+
" <td>0:0</td>\n",
|
| 974 |
+
" <td>0.014072</td>\n",
|
| 975 |
+
" </tr>\n",
|
| 976 |
+
" <tr>\n",
|
| 977 |
+
" <th>1</th>\n",
|
| 978 |
+
" <td>qp02zu</td>\n",
|
| 979 |
+
" <td>62</td>\n",
|
| 980 |
+
" <td>0:0</td>\n",
|
| 981 |
+
" <td>0.039789</td>\n",
|
| 982 |
+
" </tr>\n",
|
| 983 |
+
" <tr>\n",
|
| 984 |
+
" <th>2</th>\n",
|
| 985 |
+
" <td>qp02zt</td>\n",
|
| 986 |
+
" <td>62</td>\n",
|
| 987 |
+
" <td>0:0</td>\n",
|
| 988 |
+
" <td>0.137830</td>\n",
|
| 989 |
+
" </tr>\n",
|
| 990 |
+
" <tr>\n",
|
| 991 |
+
" <th>3</th>\n",
|
| 992 |
+
" <td>qp02zv</td>\n",
|
| 993 |
+
" <td>62</td>\n",
|
| 994 |
+
" <td>0:0</td>\n",
|
| 995 |
+
" <td>0.042405</td>\n",
|
| 996 |
+
" </tr>\n",
|
| 997 |
+
" <tr>\n",
|
| 998 |
+
" <th>4</th>\n",
|
| 999 |
+
" <td>qp08bj</td>\n",
|
| 1000 |
+
" <td>62</td>\n",
|
| 1001 |
+
" <td>0:0</td>\n",
|
| 1002 |
+
" <td>0.054124</td>\n",
|
| 1003 |
+
" </tr>\n",
|
| 1004 |
+
" </tbody>\n",
|
| 1005 |
+
"</table>\n",
|
| 1006 |
+
"</div>"
|
| 1007 |
+
],
|
| 1008 |
+
"text/plain": [
|
| 1009 |
+
" geohash6 day timestamp demand\n",
|
| 1010 |
+
"0 qp02zd 62 0:0 0.014072\n",
|
| 1011 |
+
"1 qp02zu 62 0:0 0.039789\n",
|
| 1012 |
+
"2 qp02zt 62 0:0 0.137830\n",
|
| 1013 |
+
"3 qp02zv 62 0:0 0.042405\n",
|
| 1014 |
+
"4 qp08bj 62 0:0 0.054124"
|
| 1015 |
+
]
|
| 1016 |
+
},
|
| 1017 |
+
"execution_count": 15,
|
| 1018 |
+
"metadata": {},
|
| 1019 |
+
"output_type": "execute_result"
|
| 1020 |
+
}
|
| 1021 |
+
],
|
| 1022 |
+
"source": [
|
| 1023 |
+
"df_trial = df_train[['geohash6','day','timestamp','demand']].iloc[-20000:,:]\n",
|
| 1024 |
+
"df_trial.to_csv('df_trial.csv', index=False)\n",
|
| 1025 |
+
"\n",
|
| 1026 |
+
"trial_link = 'df_trial.csv'\n",
|
| 1027 |
+
"predict5ts(link=trial_link)\n",
|
| 1028 |
+
"\n",
|
| 1029 |
+
"output = pd.read_csv('output.csv')\n",
|
| 1030 |
+
"print(output.shape)\n",
|
| 1031 |
+
"output.head()"
|
| 1032 |
+
]
|
| 1033 |
+
},
|
| 1034 |
+
{
|
| 1035 |
+
"cell_type": "code",
|
| 1036 |
+
"execution_count": 16,
|
| 1037 |
+
"metadata": {},
|
| 1038 |
+
"outputs": [],
|
| 1039 |
+
"source": [
|
| 1040 |
+
"os.remove(\"df_trial.csv\")\n",
|
| 1041 |
+
"os.remove(\"output.csv\")"
|
| 1042 |
+
]
|
| 1043 |
+
},
|
| 1044 |
+
{
|
| 1045 |
+
"cell_type": "markdown",
|
| 1046 |
+
"metadata": {},
|
| 1047 |
+
"source": [
|
| 1048 |
+
"## Part 4 - Predict demands of T+1, ..., T+5 using test data\n",
|
| 1049 |
+
"* Please uncomment below code and enter the link of test data.\n",
|
| 1050 |
+
"* Below code will produce an output file **output.csv** which is the demand forecast of T+1,...,T+5 for all the geo-locations, where T is the last time stamp in the test data."
|
| 1051 |
+
]
|
| 1052 |
+
},
|
| 1053 |
+
{
|
| 1054 |
+
"cell_type": "code",
|
| 1055 |
+
"execution_count": 17,
|
| 1056 |
+
"metadata": {},
|
| 1057 |
+
"outputs": [],
|
| 1058 |
+
"source": [
|
| 1059 |
+
"#test_link = '...'\n",
|
| 1060 |
+
"#predict5ts(link=test_link)"
|
| 1061 |
+
]
|
| 1062 |
+
}
|
| 1063 |
+
],
|
| 1064 |
+
"metadata": {
|
| 1065 |
+
"kernelspec": {
|
| 1066 |
+
"display_name": "Python 3",
|
| 1067 |
+
"language": "python",
|
| 1068 |
+
"name": "python3"
|
| 1069 |
+
},
|
| 1070 |
+
"language_info": {
|
| 1071 |
+
"codemirror_mode": {
|
| 1072 |
+
"name": "ipython",
|
| 1073 |
+
"version": 3
|
| 1074 |
+
},
|
| 1075 |
+
"file_extension": ".py",
|
| 1076 |
+
"mimetype": "text/x-python",
|
| 1077 |
+
"name": "python",
|
| 1078 |
+
"nbconvert_exporter": "python",
|
| 1079 |
+
"pygments_lexer": "ipython3",
|
| 1080 |
+
"version": "3.6.4"
|
| 1081 |
+
}
|
| 1082 |
+
},
|
| 1083 |
+
"nbformat": 4,
|
| 1084 |
+
"nbformat_minor": 1
|
| 1085 |
+
}
|