{"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":"code","source":"import pandas as pd\nimport numpy as np\nimport gc\nimport lightgbm as lgbm\n\nfrom matplotlib import pyplot as plt \n\nfrom sklearn.metrics import mean_absolute_error\n\nfrom datetime import datetime, timedelta\nfrom tqdm.auto import tqdm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-31T11:15:43.628607Z","iopub.execute_input":"2021-07-31T11:15:43.629017Z","iopub.status.idle":"2021-07-31T11:15:45.999898Z","shell.execute_reply.started":"2021-07-31T11:15:43.628930Z","shell.execute_reply":"2021-07-31T11:15:45.998800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Unnested Dataset","metadata":{}},{"cell_type":"code","source":"df_train = pd.read_csv('../input/mlb-player-digital-engagement-forecasting/train_updated.csv')\nprint(df_train.shape)\ndf_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:15:46.001449Z","iopub.execute_input":"2021-07-31T11:15:46.001804Z","iopub.status.idle":"2021-07-31T11:17:14.638873Z","shell.execute_reply.started":"2021-07-31T11:15:46.001767Z","shell.execute_reply":"2021-07-31T11:17:14.637918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.info()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:14.640526Z","iopub.execute_input":"2021-07-31T11:17:14.640816Z","iopub.status.idle":"2021-07-31T11:17:14.667030Z","shell.execute_reply.started":"2021-07-31T11:17:14.640788Z","shell.execute_reply":"2021-07-31T11:17:14.665995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def json_to_df(df, column):\n    num_rows = len(df)\n    \n    data_list = []\n    for row in tqdm(range(num_rows)):\n        \n        json_data = df.iloc[row][column]\n        if str(json_data) != \"nan\":\n            data = pd.read_json(json_data)\n            data_list.append(data)\n        \n    all_data = pd.concat(data_list, axis = 0)\n    \n    return all_data","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:14.670492Z","iopub.execute_input":"2021-07-31T11:17:14.670931Z","iopub.status.idle":"2021-07-31T11:17:14.676832Z","shell.execute_reply.started":"2021-07-31T11:17:14.670899Z","shell.execute_reply":"2021-07-31T11:17:14.676081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"player_engagement = json_to_df(df_train, 'nextDayPlayerEngagement')\nplayer_engagement.insert(0, 'date', pd.to_datetime(player_engagement['engagementMetricsDate'])-\\\n                                                   timedelta(days=1))\nplayer_engagement['engagementMetricsDate'] = pd.to_datetime(player_engagement['engagementMetricsDate'])\nplayer_engagement.reset_index(drop=True, inplace=True)\nprint(player_engagement.shape)\nplayer_engagement.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:14.677846Z","iopub.execute_input":"2021-07-31T11:17:14.678247Z","iopub.status.idle":"2021-07-31T11:17:42.365003Z","shell.execute_reply.started":"2021-07-31T11:17:14.678218Z","shell.execute_reply":"2021-07-31T11:17:42.364047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"player_engagement[['target1','target2','target3','target4']] = player_engagement[['target1','target2','target3','target4']].astype(np.float16)","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:42.366217Z","iopub.execute_input":"2021-07-31T11:17:42.366542Z","iopub.status.idle":"2021-07-31T11:17:42.564321Z","shell.execute_reply.started":"2021-07-31T11:17:42.366510Z","shell.execute_reply":"2021-07-31T11:17:42.563339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Lag Features","metadata":{}},{"cell_type":"code","source":"lag = 7\n\nlag_df = player_engagement.loc[player_engagement['date'] >= player_engagement.loc[0, 'date'] +\\\n                               timedelta(lag)]\n\nfor x in tqdm(range(1, (lag+1))):\n    drop_columns = [f'date_{x}', f'engagementMetricsDate_{x}']\n    lag_df = lag_df.merge(player_engagement, how='left', \n                          left_on=['date', 'playerId'],\n                          right_on=['engagementMetricsDate', 'playerId'],\n                          suffixes=['',f'_{x}'])\n    lag_df.drop(columns=drop_columns, inplace=True)\n    lag_df['date'] = lag_df['date'] - timedelta(days=1)\n    \nlag_df['date'] = lag_df['date'] + timedelta(days=lag)\nlag_df = lag_df.drop(columns=['engagementMetricsDate'])\nlag_df = lag_df.dropna()\nlag_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:42.565504Z","iopub.execute_input":"2021-07-31T11:17:42.565808Z","iopub.status.idle":"2021-07-31T11:17:54.158374Z","shell.execute_reply.started":"2021-07-31T11:17:42.565779Z","shell.execute_reply":"2021-07-31T11:17:54.157394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"feature_columns = [x for x in lag_df.columns[6:]]\nfeature_columns","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:54.160632Z","iopub.execute_input":"2021-07-31T11:17:54.160927Z","iopub.status.idle":"2021-07-31T11:17:54.166677Z","shell.execute_reply.started":"2021-07-31T11:17:54.160897Z","shell.execute_reply":"2021-07-31T11:17:54.165868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lag_df.info()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:54.168212Z","iopub.execute_input":"2021-07-31T11:17:54.168662Z","iopub.status.idle":"2021-07-31T11:17:54.191504Z","shell.execute_reply.started":"2021-07-31T11:17:54.168615Z","shell.execute_reply":"2021-07-31T11:17:54.190293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lag_df = lag_df.sort_values(by=['date','playerId']).reset_index(drop=True)\nlag_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:54.192824Z","iopub.execute_input":"2021-07-31T11:17:54.193124Z","iopub.status.idle":"2021-07-31T11:17:55.511978Z","shell.execute_reply.started":"2021-07-31T11:17:54.193095Z","shell.execute_reply":"2021-07-31T11:17:55.511141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Descriptive Statistics Based on Lag Features","metadata":{}},{"cell_type":"code","source":"for x in range(4):\n    columns = [f'target{x+1}_{i+1}' for i in range(lag)]\n    lag_df[f'target{x+1}_median'] = lag_df[columns].median(axis=1).astype(np.float32)\n    lag_df[f'target{x+1}_mean'] = lag_df[columns].mean(axis=1).astype(np.float32)\n    lag_df[f'target{x+1}_max'] = lag_df[columns].max(axis=1).astype(np.float32)\n    lag_df[f'target{x+1}_min'] = lag_df[columns].min(axis=1).astype(np.float32)\n    lag_df[f'target{x+1}_lower_quartile'] = lag_df[columns].quantile(0.25, axis=1).astype(np.float32)\n    lag_df[f'target{x+1}_upper_quartile'] = lag_df[columns].quantile(0.75, axis=1).astype(np.float32)\n    lag_df[f'target{x+1}_skewness'] = lag_df[columns].skew(axis=1).astype(np.float32)\n    lag_df = lag_df.drop(columns=columns)","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:17:55.513240Z","iopub.execute_input":"2021-07-31T11:17:55.513735Z","iopub.status.idle":"2021-07-31T11:18:20.259403Z","shell.execute_reply.started":"2021-07-31T11:17:55.513702Z","shell.execute_reply":"2021-07-31T11:18:20.258642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lag_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:20.260769Z","iopub.execute_input":"2021-07-31T11:18:20.261246Z","iopub.status.idle":"2021-07-31T11:18:20.288168Z","shell.execute_reply.started":"2021-07-31T11:18:20.261213Z","shell.execute_reply":"2021-07-31T11:18:20.287467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lag_df.shape","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:20.289281Z","iopub.execute_input":"2021-07-31T11:18:20.289681Z","iopub.status.idle":"2021-07-31T11:18:20.295127Z","shell.execute_reply.started":"2021-07-31T11:18:20.289646Z","shell.execute_reply":"2021-07-31T11:18:20.294194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target_columns = [x for x in lag_df.columns[2:6]]\ntarget_columns","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:20.296359Z","iopub.execute_input":"2021-07-31T11:18:20.296710Z","iopub.status.idle":"2021-07-31T11:18:20.312384Z","shell.execute_reply.started":"2021-07-31T11:18:20.296681Z","shell.execute_reply":"2021-07-31T11:18:20.311086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"feature_columns = [x for x in lag_df.columns[6:]]\nfeature_columns","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:20.313830Z","iopub.execute_input":"2021-07-31T11:18:20.314151Z","iopub.status.idle":"2021-07-31T11:18:20.329002Z","shell.execute_reply.started":"2021-07-31T11:18:20.314119Z","shell.execute_reply":"2021-07-31T11:18:20.327868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train LightGBM Model","metadata":{}},{"cell_type":"code","source":"def lgbm_fit(X_train, y_train, X_val, y_val, params):\n    model = lgbm.LGBMRegressor(**params)\n    model.fit(\n        X_train,\n        y_train,\n        eval_set=[(X_val, y_val)],\n        early_stopping_rounds=100, \n        verbose=100\n    )\n    \n    pred = model.predict(X_val)\n    \n    score = mean_absolute_error(pred, y_val)\n    \n    return model, score","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:20.330776Z","iopub.execute_input":"2021-07-31T11:18:20.331284Z","iopub.status.idle":"2021-07-31T11:18:20.341017Z","shell.execute_reply.started":"2021-07-31T11:18:20.331249Z","shell.execute_reply":"2021-07-31T11:18:20.340283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create training and validation dataset for training \ntrain_index = lag_df.loc[lag_df['date']<datetime(2021,5,1), feature_columns].index.to_numpy()\nval_index = lag_df.loc[lag_df['date']>=datetime(2021,5,1), feature_columns].index.to_numpy()\n\nX_train = lag_df.loc[train_index, feature_columns].to_numpy()\ny_train = lag_df.loc[train_index, target_columns]\n    \nX_val = lag_df.loc[val_index, feature_columns].to_numpy()\ny_val = lag_df.loc[val_index, target_columns]","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:20.341988Z","iopub.execute_input":"2021-07-31T11:18:20.342383Z","iopub.status.idle":"2021-07-31T11:18:21.514448Z","shell.execute_reply.started":"2021-07-31T11:18:20.342354Z","shell.execute_reply":"2021-07-31T11:18:21.513628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Some parameters values below are copy-pasted from this [notebook](https://www.kaggle.com/lhagiimn/lightgbm-catboost-ann-2505f2) by [lhagiimn](https://www.kaggle.com/lhagiimn) at cell 14.","metadata":{}},{"cell_type":"code","source":"params = {\n    'boosting_type': 'gbrt',\n    'objective':'mae',\n#     'subsample': 0.5,\n#     'subsample_freq': 1,\n    'learning_rate': 0.03,\n    'num_leaves': 2**11-1,\n    'min_data_in_leaf': 2**12-1,\n#     'feature_fraction': 0.5,\n    'max_bin': 200,\n    'n_estimators': 2500,\n#     'boost_from_average': False,\n    \"random_seed\":42,\n}\n\nlgbm_model1, score1 = lgbm_fit(X_train, y_train['target1'], X_val, y_val['target1'], params)\n\nlgbm_model2, score2 = lgbm_fit(X_train, y_train['target2'], X_val, y_val['target2'], params)\n\nlgbm_model3, score3 = lgbm_fit(X_train, y_train['target3'], X_val, y_val['target3'], params)\n\nlgbm_model4, score4 = lgbm_fit(X_train, y_train['target4'], X_val, y_val['target4'], params)\n\nscore = (score1+score2+score3+score4)/4\nprint(f'Overall MAE Score:{score}')\n\n#0.7293","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:18:21.515545Z","iopub.execute_input":"2021-07-31T11:18:21.515994Z","iopub.status.idle":"2021-07-31T11:39:46.277181Z","shell.execute_reply.started":"2021-07-31T11:18:21.515962Z","shell.execute_reply":"2021-07-31T11:39:46.275747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Plotting Prediction Result","metadata":{}},{"cell_type":"code","source":"def plot_target_pred(playerId, model, target=1):\n    x1 = lag_df[lag_df['playerId'].isin([playerId])]\n    x2 = x1[x1['date']>=datetime(2021,5,1)]\n    \n    pred = model.predict(x2[feature_columns])\n    \n    plt.figure(figsize=(20,6))\n    plt.plot(x1['date'], x1[f'target{target}'])\n    plt.plot(x2['date'], pred)\n    plt.xlabel(f'date')\n    plt.ylabel(f'target')\n    plt.title(f'playerId {playerId}')\n    plt.legend([f'target{target}', 'pred'], loc='upper right')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:39:46.280144Z","iopub.execute_input":"2021-07-31T11:39:46.280538Z","iopub.status.idle":"2021-07-31T11:39:46.289794Z","shell.execute_reply.started":"2021-07-31T11:39:46.280490Z","shell.execute_reply":"2021-07-31T11:39:46.288563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plotting prediction result\n# for example, playerId = 593590\nplayerId = 593590\nplot_target_pred(playerId, lgbm_model1, target=1)\nplot_target_pred(playerId, lgbm_model2, target=2)\nplot_target_pred(playerId, lgbm_model3, target=3)\nplot_target_pred(playerId, lgbm_model4, target=4)","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:39:46.291396Z","iopub.execute_input":"2021-07-31T11:39:46.291727Z","iopub.status.idle":"2021-07-31T11:39:47.531313Z","shell.execute_reply.started":"2021-07-31T11:39:46.291697Z","shell.execute_reply":"2021-07-31T11:39:47.530251Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Target Inference","metadata":{}},{"cell_type":"code","source":"def prediction(df):\n    df = df.reset_index()\n    df['date'] = pd.to_datetime(df['date'], format='%Y%m%d')\n    df['playerId'] = df['date_playerId'].apply(lambda x: x.split('_')[1]).astype(int)\n    \n    for x in range(lag):\n        df['date'] = df['date'] - timedelta(days=1)\n        df = df.merge(player_engagement, how='left', on=['date', 'playerId'], suffixes=['',f'_{x+1}'])\n        df = df.fillna(0.)\n    \n    for x in range(4):\n        columns = [f'target{x+1}_{i+1}' for i in range(lag)]\n        df[f'target{x+1}_median'] = df[columns].median(axis=1)\n        df[f'target{x+1}_mean'] = df[columns].mean(axis=1)\n        df[f'target{x+1}_max'] = df[columns].max(axis=1)\n        df[f'target{x+1}_min'] = df[columns].min(axis=1)\n        df[f'target{x+1}_lower_quartile'] = df[columns].quantile(0.25, axis=1)\n        df[f'target{x+1}_upper_quartile'] = df[columns].quantile(0.75, axis=1)\n        df[f'target{x+1}_skewness'] = df[columns].skew(axis=1)\n        df = df.drop(columns=columns)\n        \n    target1_pred = lgbm_model1.predict(df[feature_columns].to_numpy())\n    target2_pred = lgbm_model2.predict(df[feature_columns].to_numpy())\n    target3_pred = lgbm_model3.predict(df[feature_columns].to_numpy())\n    target4_pred = lgbm_model4.predict(df[feature_columns].to_numpy())\n    \n    return target1_pred, target2_pred, target3_pred, target4_pred","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:39:47.532968Z","iopub.execute_input":"2021-07-31T11:39:47.533559Z","iopub.status.idle":"2021-07-31T11:39:47.553121Z","shell.execute_reply.started":"2021-07-31T11:39:47.533510Z","shell.execute_reply":"2021-07-31T11:39:47.551838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"player_engagement = player_engagement.drop(columns=['engagementMetricsDate'])","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:39:47.554745Z","iopub.execute_input":"2021-07-31T11:39:47.555049Z","iopub.status.idle":"2021-07-31T11:39:47.617822Z","shell.execute_reply.started":"2021-07-31T11:39:47.555021Z","shell.execute_reply":"2021-07-31T11:39:47.616371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import mlb\n\nenv = mlb.make_env() # initialize the environment\niter_test = env.iter_test() # iterator which loops over each date in test set\n\nfor (test_df, sample_prediction_df) in iter_test:\n    target1, target2, target3, target4 = prediction(sample_prediction_df)\n    sample_prediction_df['target1'] = np.clip(target1, 0, 100)\n    sample_prediction_df['target2'] = np.clip(target2, 0, 100)\n    sample_prediction_df['target3'] = np.clip(target3, 0, 100)\n    sample_prediction_df['target4'] = np.clip(target4, 0, 100)\n    env.predict(sample_prediction_df)","metadata":{"execution":{"iopub.status.busy":"2021-07-31T11:39:47.622436Z","iopub.execute_input":"2021-07-31T11:39:47.622904Z","iopub.status.idle":"2021-07-31T11:40:06.622239Z","shell.execute_reply.started":"2021-07-31T11:39:47.622857Z","shell.execute_reply":"2021-07-31T11:40:06.621090Z"},"trusted":true},"execution_count":null,"outputs":[]}]}