{"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 numpy as np\nimport pandas as pd\nimport os\nimport pickle\nimport gc\n\nfrom sklearn.metrics import mean_absolute_error\nimport lightgbm as lgbm\n\npd.set_option('display.max_columns', 100)","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:26.000691Z","iopub.execute_input":"2021-07-09T01:08:26.001518Z","iopub.status.idle":"2021-07-09T01:08:28.392218Z","shell.execute_reply.started":"2021-07-09T01:08:26.001377Z","shell.execute_reply":"2021-07-09T01:08:28.390977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# trainの中身をcsv, pickleにしてくれている親切なデータセットがあったので使います\nbase_dir = '../input/mlb-player-digital-engagement-forecasting/'\ntrain_dir = '../input/mlb-pdef-train-dataset/'","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:28.393806Z","iopub.execute_input":"2021-07-09T01:08:28.394113Z","iopub.status.idle":"2021-07-09T01:08:28.399857Z","shell.execute_reply.started":"2021-07-09T01:08:28.394085Z","shell.execute_reply":"2021-07-09T01:08:28.398527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# このtarget1～4を予測するのがコンペの目的\ntarget_df = pd.read_pickle(train_dir + 'nextDayPlayerEngagement_train.pkl')\ntarget_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:28.402148Z","iopub.execute_input":"2021-07-09T01:08:28.402519Z","iopub.status.idle":"2021-07-09T01:08:30.852058Z","shell.execute_reply.started":"2021-07-09T01:08:28.402491Z","shell.execute_reply":"2021-07-09T01:08:30.850743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target_df.info()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:30.853762Z","iopub.execute_input":"2021-07-09T01:08:30.854081Z","iopub.status.idle":"2021-07-09T01:08:30.874735Z","shell.execute_reply.started":"2021-07-09T01:08:30.854052Z","shell.execute_reply":"2021-07-09T01:08:30.873263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 2061選手分の、1216件のデータがある\ntarget_df.nunique()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:30.876476Z","iopub.execute_input":"2021-07-09T01:08:30.876793Z","iopub.status.idle":"2021-07-09T01:08:31.846496Z","shell.execute_reply.started":"2021-07-09T01:08:30.876763Z","shell.execute_reply":"2021-07-09T01:08:31.845405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# target encoding以外の特徴量はこのnotebookを参照\n# https://www.kaggle.com/mlconsult/1-38-lb-lightgbm-with-target-statistics\n\nplayers = pd.read_csv(base_dir + 'players.csv')\nrosters = pd.read_pickle(train_dir + 'rosters_train.pkl')\nscores = pd.read_pickle(train_dir + 'playerBoxScores_train.pkl')\nscores = scores.groupby(['playerId', 'date']).sum().reset_index()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:31.847894Z","iopub.execute_input":"2021-07-09T01:08:31.848176Z","iopub.status.idle":"2021-07-09T01:08:34.774784Z","shell.execute_reply.started":"2021-07-09T01:08:31.848148Z","shell.execute_reply":"2021-07-09T01:08:34.773592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 効きそうなカラムを抽出\ntargets_cols = ['playerId', 'target1', 'target2', 'target3', 'target4', 'date']\nplayers_cols = ['playerId', 'primaryPositionName']\nrosters_cols = ['playerId', 'teamId', 'status', 'date']\nscores_cols = ['playerId', 'battingOrder', 'gamesPlayedBatting', 'flyOuts',\n               'groundOuts', 'runsScored', 'doubles', 'triples', 'homeRuns',\n               'strikeOuts', 'baseOnBalls', 'intentionalWalks', 'hits', 'hitByPitch',\n               'atBats', 'caughtStealing', 'stolenBases', 'groundIntoDoublePlay',\n               'groundIntoTriplePlay', 'plateAppearances', 'totalBases', 'rbi',\n               'leftOnBase', 'sacBunts', 'sacFlies', 'catchersInterference',\n               'pickoffs', 'gamesPlayedPitching', 'gamesStartedPitching',\n               'completeGamesPitching', 'shutoutsPitching', 'winsPitching',\n               'lossesPitching', 'flyOutsPitching', 'airOutsPitching',\n               'groundOutsPitching', 'runsPitching', 'doublesPitching',\n               'triplesPitching', 'homeRunsPitching', 'strikeOutsPitching',\n               'baseOnBallsPitching', 'intentionalWalksPitching', 'hitsPitching',\n               'hitByPitchPitching', 'atBatsPitching', 'caughtStealingPitching',\n               'stolenBasesPitching', 'inningsPitched', 'saveOpportunities',\n               'earnedRuns', 'battersFaced', 'outsPitching', 'pitchesThrown', 'balls',\n               'strikes', 'hitBatsmen', 'balks', 'wildPitches', 'pickoffsPitching',\n               'rbiPitching', 'gamesFinishedPitching', 'inheritedRunners',\n               'inheritedRunnersScored', 'catchersInterferencePitching',\n               'sacBuntsPitching', 'sacFliesPitching', 'saves', 'holds', 'blownSaves',\n               'assists', 'putOuts', 'errors', 'chances', 'date']\n\ntarget_stat_cols = ['playerId', 'target1_mean', 'target1_median', 'target1_std', 'target1_max', 'target1_min', \n                       'target2_mean', 'target2_median', 'target2_std', 'target2_max', 'target2_min', \n                       'target3_mean', 'target3_median', 'target3_std', 'target3_max', 'target3_min', \n                       'target4_mean', 'target4_median', 'target4_std', 'target4_max', 'target4_min']\n\nfeature_cols = ['label_playerId', 'label_primaryPositionName', 'label_teamId',\n                'label_status', 'battingOrder', 'gamesPlayedBatting', 'flyOuts',\n                'groundOuts', 'runsScored', 'doubles', 'triples', 'homeRuns',\n                'strikeOuts', 'baseOnBalls', 'intentionalWalks', 'hits', 'hitByPitch',\n                'atBats', 'caughtStealing', 'stolenBases', 'groundIntoDoublePlay',\n                'groundIntoTriplePlay', 'plateAppearances', 'totalBases', 'rbi',\n                'leftOnBase', 'sacBunts', 'sacFlies', 'catchersInterference',\n                'pickoffs', 'gamesPlayedPitching', 'gamesStartedPitching',\n                'completeGamesPitching', 'shutoutsPitching', 'winsPitching',\n                'lossesPitching', 'flyOutsPitching', 'airOutsPitching',\n                'groundOutsPitching', 'runsPitching', 'doublesPitching',\n                'triplesPitching', 'homeRunsPitching', 'strikeOutsPitching',\n                'baseOnBallsPitching', 'intentionalWalksPitching', 'hitsPitching',\n                'hitByPitchPitching', 'atBatsPitching', 'caughtStealingPitching',\n                'stolenBasesPitching', 'inningsPitched', 'saveOpportunities',\n                'earnedRuns', 'battersFaced', 'outsPitching', 'pitchesThrown', 'balls',\n                'strikes', 'hitBatsmen', 'balks', 'wildPitches', 'pickoffsPitching',\n                'rbiPitching', 'gamesFinishedPitching', 'inheritedRunners',\n                'inheritedRunnersScored', 'catchersInterferencePitching',\n                'sacBuntsPitching', 'sacFliesPitching', 'saves', 'holds', 'blownSaves',\n                'assists', 'putOuts', 'errors', 'chances', \n                'target1_mean', 'target1_median', 'target1_std', 'target1_max', 'target1_min', \n                'target2_mean', 'target2_median', 'target2_std', 'target2_max', 'target2_min', \n                'target3_mean', 'target3_median', 'target3_std', 'target3_max', 'target3_min', \n                'target4_mean', 'target4_median', 'target4_std', 'target4_max', 'target4_min']","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:09:14.142684Z","iopub.execute_input":"2021-07-09T01:09:14.143122Z","iopub.status.idle":"2021-07-09T01:09:14.159906Z","shell.execute_reply.started":"2021-07-09T01:09:14.143086Z","shell.execute_reply":"2021-07-09T01:09:14.159027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 結合\ndf = target_df[targets_cols]\n\ndf = df.merge(players[players_cols], on=['playerId'], how='left')\ndf = df.merge(rosters[rosters_cols], on=['playerId', 'date'], how='left')\ndf = df.merge(scores[scores_cols], on=['playerId', 'date'], how='left')\n\n# label encoding\nplayer2num = {c: i for i, c in enumerate(df['playerId'].unique())}\nposition2num = {c: i for i, c in enumerate(df['primaryPositionName'].unique())}\nteamid2num = {c: i for i, c in enumerate(df['teamId'].unique())}\nstatus2num = {c: i for i, c in enumerate(df['status'].unique())}\ndf['label_playerId'] = df['playerId'].map(player2num)\ndf['label_primaryPositionName'] = df['primaryPositionName'].map(position2num)\ndf['label_teamId'] = df['teamId'].map(teamid2num)\ndf['label_status'] = df['status'].map(status2num)\n\n\ndel rosters, scores\ngc.collect()\n\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:34.802568Z","iopub.execute_input":"2021-07-09T01:08:34.802923Z","iopub.status.idle":"2021-07-09T01:08:39.596916Z","shell.execute_reply.started":"2021-07-09T01:08:34.802886Z","shell.execute_reply":"2021-07-09T01:08:39.595749Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('player2num.pkl', 'wb') as f:\n    pickle.dump(player2num, f)\n\nwith open('position2num.pkl', 'wb') as f:\n    pickle.dump(position2num, f)\n\nwith open('teamid2num.pkl', 'wb') as f:\n    pickle.dump(teamid2num, f)\n\nwith open('status2num.pkl', 'wb') as f:\n    pickle.dump(status2num, f)\n    \ndel player2num, position2num, teamid2num, status2num","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:39.599290Z","iopub.execute_input":"2021-07-09T01:08:39.599715Z","iopub.status.idle":"2021-07-09T01:08:39.618469Z","shell.execute_reply.started":"2021-07-09T01:08:39.599669Z","shell.execute_reply":"2021-07-09T01:08:39.617090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# seasonのみのモデルを作成するため4~9月のデータのみ抜き出し\nprint('before:', df.shape)\ndf['month'] = df['date'].astype('str').str[4:6].astype('int')\ndf = df[(4<=df['month']) & (df['month']<=9)]\nprint('after:', df.shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:39.620252Z","iopub.execute_input":"2021-07-09T01:08:39.620674Z","iopub.status.idle":"2021-07-09T01:08:47.096250Z","shell.execute_reply.started":"2021-07-09T01:08:39.620631Z","shell.execute_reply":"2021-07-09T01:08:47.095106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# target encoding用データセット作成\n# 直近のデータで作成するが、これでは特徴量の意味が変わると思いつつ一番精度が良い\ntarget_stat_df = df.loc[df['date']>=20210331, ['playerId', 'target1', 'target2', 'target3', 'target4']]\ntarget_stat_df = target_stat_df.groupby('playerId').agg(['mean', 'median', 'std', 'max', 'min'])","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:47.097757Z","iopub.execute_input":"2021-07-09T01:08:47.098382Z","iopub.status.idle":"2021-07-09T01:08:47.164389Z","shell.execute_reply.started":"2021-07-09T01:08:47.098336Z","shell.execute_reply":"2021-07-09T01:08:47.163010Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target_stat_df","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:47.165913Z","iopub.execute_input":"2021-07-09T01:08:47.166252Z","iopub.status.idle":"2021-07-09T01:08:47.211639Z","shell.execute_reply.started":"2021-07-09T01:08:47.166219Z","shell.execute_reply":"2021-07-09T01:08:47.210337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target_stat_df = target_stat_df.reset_index()\ntarget_stat_df.columns = target_stat_cols\ntarget_stat_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:47.213687Z","iopub.execute_input":"2021-07-09T01:08:47.214156Z","iopub.status.idle":"2021-07-09T01:08:47.248485Z","shell.execute_reply.started":"2021-07-09T01:08:47.214106Z","shell.execute_reply":"2021-07-09T01:08:47.247410Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target_stat_df.to_pickle('target_stat_df.pkl')","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:47.250269Z","iopub.execute_input":"2021-07-09T01:08:47.250606Z","iopub.status.idle":"2021-07-09T01:08:47.348130Z","shell.execute_reply.started":"2021-07-09T01:08:47.250574Z","shell.execute_reply":"2021-07-09T01:08:47.346661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = df.merge(target_stat_df[target_stat_cols], how='left', on='playerId')\n\ndel target_stat_df\ngc.collect()\n\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:47.349721Z","iopub.execute_input":"2021-07-09T01:08:47.350019Z","iopub.status.idle":"2021-07-09T01:08:49.652557Z","shell.execute_reply.started":"2021-07-09T01:08:47.349985Z","shell.execute_reply":"2021-07-09T01:08:49.651113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_X = df[feature_cols]\ndf_y = df[['target1', 'target2', 'target3', 'target4']]\n\n_index = (df['date'] < 20210401)\nx_train = df_X.loc[_index].reset_index(drop=True)\ny_train = df_y.loc[_index].reset_index(drop=True)\nx_valid = df_X.loc[~_index].reset_index(drop=True)\ny_valid = df_y.loc[~_index].reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:09:18.031401Z","iopub.execute_input":"2021-07-09T01:09:18.031988Z","iopub.status.idle":"2021-07-09T01:09:20.602946Z","shell.execute_reply.started":"2021-07-09T01:09:18.031950Z","shell.execute_reply":"2021-07-09T01:09:20.602210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('training data shape:' , x_train.shape, y_train.shape)\nprint('validation data shape:' , x_valid.shape, y_valid.shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:09:21.500609Z","iopub.execute_input":"2021-07-09T01:09:21.501018Z","iopub.status.idle":"2021-07-09T01:09:21.507834Z","shell.execute_reply.started":"2021-07-09T01:09:21.500980Z","shell.execute_reply":"2021-07-09T01:09:21.506573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import lightgbm as lgbm\ndef fit_lgbm(x_train, y_train, x_valid, y_valid, params: dict=None, verbose=100):\n    oof_pred = np.zeros(len(y_valid), dtype=np.float32)\n    model = lgbm.LGBMRegressor(**params)\n    model.fit(x_train, y_train, \n        eval_set=[(x_valid, y_valid)],  \n        early_stopping_rounds=verbose, \n        verbose=verbose)\n    oof_pred = model.predict(x_valid)\n    score = mean_absolute_error(oof_pred, y_valid)\n    print('mae:', score)\n    return oof_pred, model, score\n\n\n# training lightgbm\nparams = {\n 'objective':'mae',\n 'reg_alpha': 0.1,\n 'reg_lambda': 0.1, \n 'n_estimators': 100000,\n 'learning_rate': 0.1,\n 'random_state': 42,\n}\n\noof1, model1, score1 = fit_lgbm(\n    x_train, y_train['target1'],\n    x_valid, y_valid['target1'],\n    params\n)\noof2, model2, score2 = fit_lgbm(\n    x_train, y_train['target2'],\n    x_valid, y_valid['target2'],\n    params\n)\noof3, model3, score3 = fit_lgbm(\n    x_train, y_train['target3'],\n    x_valid, y_valid['target3'],\n    params\n)\noof4, model4, score4 = fit_lgbm(\n    x_train, y_train['target4'],\n    x_valid, y_valid['target4'],\n    params\n)\n\nscore = (score1+score2+score3+score4) / 4\nprint(f'score: {score}')","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:09:23.088586Z","iopub.execute_input":"2021-07-09T01:09:23.088945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('model1.pkl', 'wb') as f:\n    pickle.dump(model1, f)\n    \nwith open('model2.pkl', 'wb') as f:\n    pickle.dump(model2, f)\n    \nwith open('model3.pkl', 'wb') as f:\n    pickle.dump(model3, f)\n    \nwith open('model4.pkl', 'wb') as f:\n    pickle.dump(model4, f)","metadata":{"execution":{"iopub.status.busy":"2021-07-09T01:08:49.806497Z","iopub.status.idle":"2021-07-09T01:08:49.806918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}