{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# MLB API Emulator with Offline Scoring\n## credit: https://www.kaggle.com/nyanpn/api-emulator-for-debugging-your-code-locally\n\nThis simple script is built upon work from [nyanpn](https://www.kaggle.com/nyanpn), with a scoring function. If you set `eval_start_day=20210501` and `eval_end_day=20210531`, and then call `get_pb_score()`, the emulator will return a score as if you submit to the public leaderboard. The score should be exactly consistent with PB score. Besides, you are welcome to set other evaluation periods for your purpose.","metadata":{}},{"cell_type":"code","source":"import os\nimport warnings\nfrom typing import Optional, Tuple\n\nimport pandas as pd\nimport json\n\n\nclass Environment:\n    def __init__(self,\n                 data_dir: str,\n                 eval_start_day: int,\n                 eval_end_day: Optional[int],\n                 use_updated: bool,\n                 multiple_days_per_iter: bool):\n        warnings.warn('this is mock module for mlb')\n\n        postfix = '_updated' if use_updated else ''\n        \n        # recommend to replace this with pickle, feather etc to speedup preparing data\n        df_train = pd.read_csv(os.path.join(data_dir, f'train{postfix}.csv'))\n\n        players = pd.read_csv(os.path.join(data_dir, 'players.csv'))\n\n        self.players = players[players['playerForTestSetAndFuturePreds'] == True]['playerId'].astype(str)\n        if eval_end_day is not None:\n            self.df_train = df_train.set_index('date').loc[eval_start_day:eval_end_day]\n        else:\n            self.df_train = df_train.set_index('date').loc[eval_start_day:]\n        self.date = self.df_train.index.values\n        self.n_rows = len(self.df_train)\n        self.multiple_days_per_iter = multiple_days_per_iter\n        self.maes = []\n        self.ws = []\n\n        assert self.n_rows > 0, 'no data to emulate'\n\n    def predict(self, df: pd.DataFrame) -> None:\n        # if you want to emulate public LB, store your prediction here and calculate MAE\n        df1 = df.copy()\n        df1[\"playerId\"] = df1[\"date_playerId\"].apply(lambda x: int(x.split(\"_\")[-1]))\n        eval_date = df1.date_playerId.iloc[0].split(\"_\")[0]\n        date = int((pd.to_datetime(eval_date, format='%Y%m%d') + pd.to_timedelta(-1, 'd')).strftime('%Y%m%d'))\n        ground_truth = pd.DataFrame(json.loads(self.df_train.nextDayPlayerEngagement.loc[date]))\n        merged = df1.merge(ground_truth, on=\"playerId\", how=\"inner\")\n        w = len(merged)\n        mae_list = []\n        for t in [1,2,3,4]:\n            mae = mean_absolute_error(merged[f\"target{t}_x\"], merged[f\"target{t}_y\"])\n            mae_list.append(mae)\n        self.maes.append(np.mean(mae_list))\n        self.ws.append(w)\n        \n    def iter_test(self) -> Tuple[pd.DataFrame, pd.DataFrame]:\n        if self.multiple_days_per_iter:\n            for i in range(self.n_rows // 2):\n                date1 = self.date[2 * i]\n                date2 = self.date[2 * i + 1]\n                sample_sub1 = self._make_sample_sub(date1)\n                sample_sub2 = self._make_sample_sub(date2)\n                sample_sub = pd.concat([sample_sub1, sample_sub2]).reset_index(drop=True)\n                df = self.df_train.loc[date1:date2]\n\n                yield df, sample_sub.set_index('date')\n        else:\n            for i in range(self.n_rows):\n                date = self.date[i]\n                sample_sub = self._make_sample_sub(date)\n                df = self.df_train.loc[date:date]\n\n                yield df, sample_sub.set_index('date')\n\n    def _make_sample_sub(self, date: int) -> pd.DataFrame:\n        next_day = (pd.to_datetime(date, format='%Y%m%d') + pd.to_timedelta(1, 'd')).strftime('%Y%m%d')\n        sample_sub = pd.DataFrame()\n        sample_sub['date_playerId'] = next_day + '_' + self.players\n        sample_sub['target1'] = 0\n        sample_sub['target2'] = 0\n        sample_sub['target3'] = 0\n        sample_sub['target4'] = 0\n        sample_sub['date'] = date\n        return sample_sub\n\n    def get_pb_score(self):\n        return np.average(self.maes, weights=self.ws)\n\nclass MLBEmulator:\n    def __init__(self,\n                 data_dir: str = '../input/mlb-player-digital-engagement-forecasting',\n                 eval_start_day: int = 20210401,\n                 eval_end_day: Optional[int] = 20210430,\n                 use_updated: bool = True,\n                 multiple_days_per_iter: bool = False):\n        self.data_dir = data_dir\n        self.eval_start_day = eval_start_day\n        self.eval_end_day = eval_end_day\n        self.use_updated = use_updated\n        self.multiple_days_per_iter = multiple_days_per_iter\n\n    def make_env(self) -> Environment:\n        return Environment(self.data_dir,\n                           self.eval_start_day,\n                           self.eval_end_day,\n                           self.use_updated,\n                           self.multiple_days_per_iter)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]}]}