{"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 xgboost as xgb\nfrom sklearn.metrics import matthews_corrcoef","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-12-15T17:35:32.011797Z","iopub.execute_input":"2022-12-15T17:35:32.012439Z","iopub.status.idle":"2022-12-15T17:35:32.572744Z","shell.execute_reply.started":"2022-12-15T17:35:32.012350Z","shell.execute_reply":"2022-12-15T17:35:32.571797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.set_option('max_columns', None)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:35:33.057779Z","iopub.execute_input":"2022-12-15T17:35:33.058497Z","iopub.status.idle":"2022-12-15T17:35:33.064001Z","shell.execute_reply.started":"2022-12-15T17:35:33.058462Z","shell.execute_reply":"2022-12-15T17:35:33.062570Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Read in Data","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv('../input/nfl-player-contact-detection/train_player_tracking.csv',\n                    usecols=['game_play','game_key','play_id','step','nfl_player_id','x_position','y_position'],\n                    dtype={'game_play':'str',\n                           'game_key':'str',\n                           'play_id':'str',\n                           'step':'str',\n                           'nfl_player_id':'str',\n                           'x_position':'float32',\n                           'y_position':'float32'})\n\nlabels = pd.read_csv('../input/nfl-player-contact-detection/train_labels.csv',\n                     usecols=['game_play','step','nfl_player_id_1','nfl_player_id_2','contact'],\n                     dtype={'game_play':'str',\n                            'step':'str',\n                            'nfl_player_id_1':'str',\n                            'nfl_player_id_2':'str',\n                            'contact':'int'})","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:35:56.028296Z","iopub.execute_input":"2022-12-15T17:35:56.028667Z","iopub.status.idle":"2022-12-15T17:36:03.144902Z","shell.execute_reply.started":"2022-12-15T17:35:56.028635Z","shell.execute_reply":"2022-12-15T17:36:03.143906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Features","metadata":{}},{"cell_type":"code","source":"player1 = train.copy()\nplayer2 = train.drop(['game_key','play_id'], axis=1).copy()\n\nplayer1.columns = ['game_play','game_key','play_id','nfl_player_id_1','step','x_position_1','y_position_1']\nplayer2.columns = ['game_play','nfl_player_id_2','step','x_position_2','y_position_2']","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:27.198914Z","iopub.execute_input":"2022-12-15T17:40:27.199285Z","iopub.status.idle":"2022-12-15T17:40:27.412241Z","shell.execute_reply.started":"2022-12-15T17:40:27.199251Z","shell.execute_reply":"2022-12-15T17:40:27.411051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(player1.shape, player2.shape, labels.shape)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:28.103335Z","iopub.execute_input":"2022-12-15T17:40:28.103706Z","iopub.status.idle":"2022-12-15T17:40:28.110376Z","shell.execute_reply.started":"2022-12-15T17:40:28.103673Z","shell.execute_reply":"2022-12-15T17:40:28.109210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# https://www.kaggle.com/code/ahmedelfazouan/nfl-player-contact-detection-helmet-track-ftrs/notebook\ndef add_step_pct(df):\n    df['step_pct'] = 100 * (df['step_int']-min(df['step_int']))/(max(df['step_int'])-min(df['step_int']))\n    df['step_pct'] = df['step_pct'].apply(np.ceil).astype(np.int16)\n    return df\n        \ndef feature_prep(pairs, tracking_1, tracking_2):\n    basetable = pd.merge(pairs, tracking_1, on=['game_play','step','nfl_player_id_1'], how='inner')\n    basetable = pd.merge(basetable, tracking_2, on=['game_play','step','nfl_player_id_2'], how='left')\n    \n    # distance between players\n    basetable['player_distances'] = np.sqrt((basetable['x_position_1'] - basetable['x_position_2'])**2 + (basetable['y_position_1'] - basetable['y_position_2'])**2)\n    \n    # Identify how far into the play each step is\n    # Used minmax scaling to do so\n    # Not all plays have the same number of steps\n    basetable['step_int'] = basetable['step'].astype('int16')\n    basetable = basetable.groupby('game_play').apply(add_step_pct)\n    \n    return basetable","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:28.673830Z","iopub.execute_input":"2022-12-15T17:40:28.674853Z","iopub.status.idle":"2022-12-15T17:40:28.686163Z","shell.execute_reply.started":"2022-12-15T17:40:28.674818Z","shell.execute_reply":"2022-12-15T17:40:28.685217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\ntrain_basetable = feature_prep(labels, player1, player2)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:29.172525Z","iopub.execute_input":"2022-12-15T17:40:29.173185Z","iopub.status.idle":"2022-12-15T17:40:41.284991Z","shell.execute_reply.started":"2022-12-15T17:40:29.173150Z","shell.execute_reply":"2022-12-15T17:40:41.283948Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X = train_basetable.drop(['game_play','step','nfl_player_id_1','nfl_player_id_2','play_id','x_position_1',\n                          'y_position_1','x_position_2','y_position_2','step_int'], axis=1)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:41.287403Z","iopub.execute_input":"2022-12-15T17:40:41.288043Z","iopub.status.idle":"2022-12-15T17:40:41.369336Z","shell.execute_reply.started":"2022-12-15T17:40:41.287999Z","shell.execute_reply":"2022-12-15T17:40:41.368107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Split data into train/val","metadata":{}},{"cell_type":"code","source":"games = list(set(X.game_key))\nN_train = int(0.8*len(games))\ntrain_games = [x for x in np.random.choice(games, N_train, replace=False)]\nval_games = list(set(games)-set(train_games))\n\ntrain_games = pd.DataFrame({'game_key':train_games})\nval_games = pd.DataFrame({'game_key':val_games})\nprint(len(games), train_games.shape[0], val_games.shape[0])","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:41.371041Z","iopub.execute_input":"2022-12-15T17:40:41.371563Z","iopub.status.idle":"2022-12-15T17:40:41.734979Z","shell.execute_reply.started":"2022-12-15T17:40:41.371521Z","shell.execute_reply":"2022-12-15T17:40:41.733952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train = pd.merge(X, train_games, on='game_key', how='inner')\nX_val = pd.merge(X, val_games, on='game_key', how='inner')\n\ny_train = X_train.contact\ny_val = X_val.contact\n\nX_train.drop(['game_key','contact'], axis=1, inplace=True)\nX_val.drop(['game_key','contact'], axis=1, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:41.737099Z","iopub.execute_input":"2022-12-15T17:40:41.738014Z","iopub.status.idle":"2022-12-15T17:40:42.625091Z","shell.execute_reply.started":"2022-12-15T17:40:41.737975Z","shell.execute_reply":"2022-12-15T17:40:42.624071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"xgb_train = xgb.DMatrix(X_train, y_train)\nxgb_val = xgb.DMatrix(X_val, y_val)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:40:42.626745Z","iopub.execute_input":"2022-12-15T17:40:42.627141Z","iopub.status.idle":"2022-12-15T17:40:43.773673Z","shell.execute_reply.started":"2022-12-15T17:40:42.627096Z","shell.execute_reply":"2022-12-15T17:40:43.772853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Model","metadata":{}},{"cell_type":"code","source":"%%time\n\nxgb_params = {'objective': 'binary:logistic',\n              'eval_metric': 'auc',\n              'learning_rate':0.01,\n              'max_depth':5,\n              'tree_method':'gpu_hist'}\n\nevals = [(xgb_train,'train'),(xgb_val,'val')]\n\nmodel = xgb.train(xgb_params, \n                  xgb_train,\n                  num_boost_round=1000,\n                  early_stopping_rounds=20, \n                  evals=evals, \n                  verbose_eval=100)\n\ntrain_preds = [x for x in model.predict(xgb_train)]\nval_preds = [x for x in model.predict(xgb_val)]\n\n# look at correlation with different thresholds \n# for defining the predicted contact labels\n# can be used to eyeball optimal threshold\n# other notebooks have been around 0.2-0.3\nthresholds = [x/100. for x in range(20, 31)]\ntrain_corrs = []\nval_corrs = []\nval_pred_rate = []\nfor thresh in thresholds:\n    train_labels = [1 if x>=thresh else 0 for x in train_preds]\n    val_labels = [1 if x>=thresh else 0 for x in val_preds]\n\n    train_corr = matthews_corrcoef(y_true=y_train, y_pred=train_labels)\n    val_corr = matthews_corrcoef(y_true=y_val, y_pred=val_labels)\n\n    train_corrs.append(train_corr)\n    val_corrs.append(val_corr)\n    val_pred_rate.append(np.mean(val_labels))\n\nthresh_results = pd.DataFrame({'thresholds':thresholds,\n                               'train_corrs':train_corrs,\n                               'val_corrs':val_corrs,\n                               'val_pred_rate':val_pred_rate})\n\nprint(thresh_results)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:41:30.236087Z","iopub.execute_input":"2022-12-15T17:41:30.236527Z","iopub.status.idle":"2022-12-15T17:43:12.338607Z","shell.execute_reply.started":"2022-12-15T17:41:30.236490Z","shell.execute_reply":"2022-12-15T17:43:12.337321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"xgb.plot_importance(model)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:43:37.573006Z","iopub.execute_input":"2022-12-15T17:43:37.573390Z","iopub.status.idle":"2022-12-15T17:43:37.815640Z","shell.execute_reply.started":"2022-12-15T17:43:37.573358Z","shell.execute_reply":"2022-12-15T17:43:37.814732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"thresh = thresh_results.sort_values('val_corrs', ascending=False)\\\n                       .reset_index(drop=True)['thresholds'][0]\nprint(thresh)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:43:41.638439Z","iopub.execute_input":"2022-12-15T17:43:41.638835Z","iopub.status.idle":"2022-12-15T17:43:41.646328Z","shell.execute_reply.started":"2022-12-15T17:43:41.638799Z","shell.execute_reply":"2022-12-15T17:43:41.645052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generate Predictions for Test Data","metadata":{}},{"cell_type":"code","source":"sub = pd.read_csv('../input/nfl-player-contact-detection/sample_submission.csv')\nsub['id_split'] = sub['contact_id'].apply(lambda x: x.split('_'))\nsub['game_play'] = sub['id_split'].apply(lambda x: x[0]+'_'+x[1])\nsub['step'] = sub['id_split'].apply(lambda x: x[2])\nsub['nfl_player_id_1'] = sub['id_split'].apply(lambda x: x[3])\nsub['nfl_player_id_2'] = sub['id_split'].apply(lambda x: x[4])","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:43:49.373464Z","iopub.execute_input":"2022-12-15T17:43:49.373890Z","iopub.status.idle":"2022-12-15T17:43:49.486531Z","shell.execute_reply.started":"2022-12-15T17:43:49.373839Z","shell.execute_reply":"2022-12-15T17:43:49.485510Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test = pd.read_csv('../input/nfl-player-contact-detection/test_player_tracking.csv',\n                   usecols=['game_play','game_key','play_id','step','nfl_player_id','x_position','y_position'],\n                   dtype={'game_play':'str',\n                          'game_key':'str',\n                          'play_id':'str',\n                          'step':'str',\n                          'nfl_player_id':'str',\n                          'x_position':'float32',\n                          'y_position':'float32'})","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:44:15.020149Z","iopub.execute_input":"2022-12-15T17:44:15.021092Z","iopub.status.idle":"2022-12-15T17:44:15.046963Z","shell.execute_reply.started":"2022-12-15T17:44:15.021045Z","shell.execute_reply":"2022-12-15T17:44:15.046041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_player1 = test.copy()\ntest_player2 = test.drop(['game_key','play_id'], axis=1).copy()\n\ntest_player1.columns = ['game_play','game_key','play_id','nfl_player_id_1','step','x_position_1','y_position_1']\ntest_player2.columns = ['game_play','nfl_player_id_2','step','x_position_2','y_position_2']","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:44:23.625303Z","iopub.execute_input":"2022-12-15T17:44:23.626047Z","iopub.status.idle":"2022-12-15T17:44:23.635149Z","shell.execute_reply.started":"2022-12-15T17:44:23.626006Z","shell.execute_reply":"2022-12-15T17:44:23.634202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_basetable = feature_prep(sub, test_player1, test_player2)","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:44:26.865020Z","iopub.execute_input":"2022-12-15T17:44:26.865396Z","iopub.status.idle":"2022-12-15T17:44:27.028649Z","shell.execute_reply.started":"2022-12-15T17:44:26.865366Z","shell.execute_reply":"2022-12-15T17:44:27.027572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_test = test_basetable.drop(['contact_id','contact','id_split','game_play','step',\n                              'nfl_player_id_1','nfl_player_id_2','game_key','play_id',\n                              'x_position_1','y_position_1','x_position_2',\n                              'y_position_2','step_int'], axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"xgb_test = xgb.DMatrix(X_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_preds = [x for x in model.predict(xgb_test)]\ntest_labels = [1 if x >= thresh else 0 for x in test_preds]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(np.mean(train_labels), np.mean(test_labels))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub['contact'] = test_labels\nsub = sub[['contact_id','contact']]\nsub.to_csv('submission.csv', header=True, index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}