Last active
May 27, 2019 17:36
-
-
Save 903124/6693fdf6b991437a6d6ef9c5d935c83b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import numpy as np\n", | |
"import pandas as pd\n", | |
"import matplotlib.pyplot as plt\n", | |
"from patsy import dmatrices\n", | |
"from sklearn.linear_model import LogisticRegression\n", | |
"\n", | |
"pbp_18 = pd.read_csv('reg_pbp_2018.csv')\n", | |
"pbp_17 = pd.read_csv('reg_pbp_2017.csv')\n", | |
"pbp_16 = pd.read_csv('reg_pbp_2016.csv')\n", | |
"\n", | |
"pbp_df = pd.concat([pbp_16,pbp_17,pbp_18])\n", | |
"pbp_df = pbp_df[['ydstogo','down','yardline_100','play_type','penalty','yards_gained','posteam','penalty_team','penalty_yards','desc','fumble_lost','touchdown','return_touchdown','field_goal_result','first_down_rush','first_down_pass','first_down_penalty','half_seconds_remaining','safety','ep','epa' ,'kick_distance','return_yards','qb_dropback','rush_attempt']]\n", | |
"pbp_df = pbp_df[pbp_df.half_seconds_remaining >= 120]\n", | |
"\n", | |
"pbp_df['inteception'] = pbp_df['desc'].apply(lambda x: 1 if 'INTERCEPTED' in x else 0)\n", | |
"pbp_df['success'] = (pbp_df.epa >0).astype(int)\n", | |
"pbp_df['first_down'] = pbp_df.first_down_rush + pbp_df.first_down_pass + pbp_df.first_down_penalty\n", | |
"pbp_df['first_down'] = pbp_df['first_down'].apply(lambda x: x == 1 if x >= 1 else 0).astype(int)\n", | |
"\n", | |
"punt_df = pbp_df[(pbp_df.down == 4) & ((pbp_df.play_type == 'punt') | (pbp_df.desc.str.contains('Punt')))]\n", | |
"fg_df = pbp_df[(pbp_df.down == 4) & ((pbp_df.play_type == 'field_goal') | (pbp_df.desc.str.contains('Field Goal')))]\n", | |
"go_for_df = pbp_df[(pbp_df.down == 4) & (~pbp_df.index.isin(punt_df.index)) & (~pbp_df.index.isin(fg_df.index))]\n", | |
"\n", | |
"punt_df['play_selection'] = 0\n", | |
"fg_df['play_selection'] = 1\n", | |
"go_for_df['play_selection'] = 2\n", | |
"\n", | |
"train_df = pd.concat([punt_df,fg_df,go_for_df])[['play_selection','yardline_100','ydstogo']]\n", | |
"\n", | |
"from patsy import dmatrices\n", | |
"\n", | |
"\n", | |
"y, X = dmatrices('play_selection ~ 0 +yardline_100 + ydstogo + ydstogo:yardline_100', train_df, return_type = 'dataframe')\n", | |
"\n", | |
"from sklearn.linear_model import LogisticRegression\n", | |
"\n", | |
"clf = LogisticRegression(random_state=0,multi_class='multinomial',max_iter=100,solver='lbfgs')\n", | |
"clf.fit(X,np.array(y).ravel())\n", | |
"\n", | |
"def sample_game_play(down,yards_to_go,yardline,opp_drive):\n", | |
" no_play = 0\n", | |
" first_down = 0\n", | |
" turnover = 0\n", | |
" field_goal = 0\n", | |
" field_goal_miss = 0\n", | |
" touch_down = 0\n", | |
" safety = 0\n", | |
" punt = 0\n", | |
" #opp_drive = 1 #toggle opimization for 1st to 3rd down\n", | |
" if(yards_to_go > 20):\n", | |
" yards_to_go = 20\n", | |
" if(down < 4):\n", | |
" if(opp_drive == 0):\n", | |
" if(down == 1 ):\n", | |
" if(random.random() < 0.7):\n", | |
" play_type = 1 #pass\n", | |
" else:\n", | |
" play_type = 0\n", | |
" elif( down == 2):\n", | |
" if(random.random() < 0.85):\n", | |
" play_type = 1\n", | |
" else:\n", | |
" play_type = 0\n", | |
" elif(down == 3):\n", | |
" if(random.random() < 0.75 and yards_to_go < 10):\n", | |
" play_type = 0\n", | |
" else:\n", | |
" play_type = 1\n", | |
"\n", | |
" if(play_type == 1):\n", | |
"\n", | |
"\n", | |
" if(yardline>= 30):\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 3) & (pbp_df.yardline_100 <= yardline + 3) & (pbp_df.qb_dropback == 1)].sample(n=1)\n", | |
" elif(yardline>= 10): \n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 2) & (pbp_df.yardline_100 <= yardline + 2)& (pbp_df.qb_dropback == 1)].sample(n=1)\n", | |
" elif(yardline>= 3):\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 1) & (pbp_df.yardline_100 <= yardline + 1)& (pbp_df.qb_dropback == 1)].sample(n=1)\n", | |
" else:\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 == yardline)& (pbp_df.qb_dropback == 1) ].sample(n=1)\n", | |
" else:\n", | |
" if(yardline>= 30):\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 3) & (pbp_df.yardline_100 <= yardline + 3)& (pbp_df.qb_dropback == 0)].sample(n=1)\n", | |
" elif(yardline>= 10): \n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 2) & (pbp_df.yardline_100 <= yardline + 2)& (pbp_df.qb_dropback == 0)].sample(n=1)\n", | |
" elif(yardline>= 3):\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 1) & (pbp_df.yardline_100 <= yardline + 1)& (pbp_df.qb_dropback == 0)].sample(n=1)\n", | |
" else:\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 == yardline) & (pbp_df.qb_dropback == 0)].sample(n=1)\n", | |
"\n", | |
" else:\n", | |
" if(yardline>= 30):\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 3) & (pbp_df.yardline_100 <= yardline + 3)].sample(n=1)\n", | |
" elif(yardline>= 10): \n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 2) & (pbp_df.yardline_100 <= yardline + 2)].sample(n=1)\n", | |
" elif(yardline>= 3):\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 >= yardline - 1) & (pbp_df.yardline_100 <= yardline + 1)].sample(n=1)\n", | |
" else:\n", | |
" chosen_play = pbp_df[(pbp_df.ydstogo == yards_to_go) & (pbp_df.down == down) & (pbp_df.yardline_100 == yardline) ].sample(n=1)\n", | |
" else:\n", | |
"\n", | |
"# play_selection = 2\n", | |
" if(opp_drive == 0): #4th down optimize\n", | |
" play_selection = fourth_down_optimal[100-int(yardline)-1,int(yards_to_go-1)]\n", | |
" else:\n", | |
" fourth_down_selection = clf.predict_proba(np.array([yardline,yards_to_go,yardline*yards_to_go]).reshape(1,-1))[0]\n", | |
" play_selection = np.random.choice(3,1,p=fourth_down_selection)[0]\n", | |
" \n", | |
" if( play_selection == 0 ): #punt\n", | |
"\n", | |
" chosen_play = pbp_df[ (pbp_df.yardline_100 >= yardline - 2) & (pbp_df.yardline_100 <= yardline + 2) & (pbp_df.play_type == 'punt') ].sample(n=1)\n", | |
" \n", | |
" elif(play_selection == 1): #field goal\n", | |
" chosen_play = pbp_df[ (pbp_df.yardline_100 >= yardline - 2) & (pbp_df.yardline_100 <= yardline + 2) & ((pbp_df.play_type == 'field_goal') )].sample(n=1)\n", | |
" else:\n", | |
" if(yardline>= 30):\n", | |
" chosen_play = pbp_df[ (pbp_df.yardline_100 >= yardline - 4) & (pbp_df.yardline_100 <= yardline + 4) & (pbp_df.ydstogo >= yards_to_go - 1) & (pbp_df.down == down) & ((pbp_df.play_type == 'pass') | (pbp_df.play_type == 'run'))].sample(n=1)\n", | |
" elif(yardline>= 10): \n", | |
" chosen_play = pbp_df[ (pbp_df.yardline_100 >= yardline - 3) & (pbp_df.yardline_100 <= yardline + 3) & (pbp_df.ydstogo >= yards_to_go - 1) & (pbp_df.down == down)& ((pbp_df.play_type == 'pass') | (pbp_df.play_type == 'run'))].sample(n=1)\n", | |
" elif(yardline>= 3):\n", | |
" chosen_play = pbp_df[ (pbp_df.yardline_100 >= yardline - 2) & (pbp_df.yardline_100 <= yardline + 2) & (pbp_df.ydstogo >= yards_to_go - 1)& (pbp_df.down == down)& ((pbp_df.play_type == 'pass') | (pbp_df.play_type == 'run')) ].sample(n=1)\n", | |
" else:\n", | |
" chosen_play = pbp_df[ (pbp_df.yardline_100 == yardline ) & (pbp_df.ydstogo == yards_to_go) & ((pbp_df.play_type == 'pass') | (pbp_df.play_type == 'run'))].sample(n=1)\n", | |
" \n", | |
" #print(chosen_play) \n", | |
" if(np.array(chosen_play['play_type'])[0] == 'no_play'):\n", | |
" no_play = 1\n", | |
" if(np.array(chosen_play['penalty'])[0] == 0):\n", | |
" yard_gain = np.array(chosen_play['yards_gained'])[0]\n", | |
" else:\n", | |
" if(np.array(chosen_play['posteam'])[0] == np.array(chosen_play['penalty_team'])[0]):\n", | |
" yard_gain = -np.array(chosen_play['penalty_yards'])[0]\n", | |
" else:\n", | |
" yard_gain = np.array(chosen_play['penalty_yards'])[0]\n", | |
" if((np.array(chosen_play.first_down_rush)[0] == 1) | (np.array(chosen_play.first_down_pass)[0] == 1) | (np.array(chosen_play.first_down_penalty)[0] == 1)):\n", | |
" first_down = 1 \n", | |
" if(np.array(chosen_play['inteception'])[0] == 1 or np.array(chosen_play['fumble_lost'])[0] == 1):\n", | |
" turnover = 1\n", | |
" yard_gain = np.array(chosen_play['yards_gained'])[0] - np.array(chosen_play['return_yards'])[0]\n", | |
" \n", | |
" if( np.array(chosen_play['play_type'])[0] == 'punt'):\n", | |
" punt = 1\n", | |
" yard_gain = np.array(chosen_play['kick_distance'])[0] - np.array(chosen_play['return_yards'])[0]\n", | |
" if(np.array(chosen_play['touchdown'])[0] == 1 and np.array(chosen_play['return_touchdown'])[0] == 0):\n", | |
" touch_down = 1\n", | |
" if(np.array(chosen_play['field_goal_result'])[0] == 'made') :\n", | |
" field_goal = 1\n", | |
" if(np.array(chosen_play['field_goal_result'])[0] == 'missed' or np.array(chosen_play['field_goal_result'])[0] == 'blocked' ) : \n", | |
" field_goal_miss = 1\n", | |
" if(np.array(chosen_play['safety'])[0] == 1) :\n", | |
" safety = 1 \n", | |
" return punt,safety,touch_down,field_goal,field_goal_miss,turnover,first_down,no_play,yard_gain,chosen_play\n", | |
"\n", | |
"\n", | |
"no_sim = 1000\n", | |
"EP_yardline = np.zeros(99)\n", | |
"for j in range(1,100):\n", | |
" print('yardline = %d' %j)\n", | |
" EP = np.zeros(no_sim)\n", | |
" for i in range(no_sim):\n", | |
" down = 1\n", | |
" \n", | |
" yards_to_go = min(10,j)\n", | |
" yardline = j\n", | |
" \n", | |
" opp_drive = 0\n", | |
" while(1):\n", | |
" try:\n", | |
"\n", | |
" punt,safety,touch_down,field_goal,field_goal_miss,turnover,first_down,no_play,yard_gain,chosen_play = sample_game_play(down,yards_to_go,yardline,opp_drive)\n", | |
"\n", | |
" except (ValueError, IndexError) as e:\n", | |
" EP[i] = 0\n", | |
" break\n", | |
" if(punt == 1):\n", | |
"\n", | |
" if(opp_drive == 0):\n", | |
"\n", | |
" if(pd.isnull(yard_gain)):\n", | |
" yardline = 80\n", | |
"\n", | |
" else:\n", | |
" yardline = max(min(100-int(yardline-yard_gain),99),1)\n", | |
"\n", | |
"\n", | |
" down = 1\n", | |
" yards_to_go = min(10,yardline)\n", | |
" opp_drive = 1 \n", | |
"\n", | |
" continue\n", | |
" else:\n", | |
" break\n", | |
" \n", | |
"\n", | |
"\n", | |
" if(field_goal == 1):\n", | |
" if(opp_drive == 0):\n", | |
"\n", | |
" EP[i] += 3\n", | |
"\n", | |
" else:\n", | |
" EP[i] -= 3\n", | |
" break\n", | |
" if(field_goal_miss == 1):\n", | |
" if(opp_drive == 0):\n", | |
" if(yardline <= 20):\n", | |
" yardline = 80\n", | |
" else:\n", | |
" \n", | |
" yardline = max(100 - (yardline +7),1)\n", | |
" \n", | |
"\n", | |
" down = 1\n", | |
" yards_to_go = min(10,yardline)\n", | |
" opp_drive = 1 \n", | |
" continue\n", | |
"\n", | |
" else:\n", | |
" break\n", | |
" \n", | |
" if(turnover == 1):\n", | |
"\n", | |
" if(touch_down == 1):\n", | |
" EP[i] -= 7 \n", | |
" break\n", | |
" else: \n", | |
" if(opp_drive == 0):\n", | |
" yardline = max(min(100-int(yardline-yard_gain),99),1)\n", | |
" down = 1\n", | |
" yards_to_go = min(10,yardline)\n", | |
" opp_drive = 1 \n", | |
" continue\n", | |
"\n", | |
" else:\n", | |
" break\n", | |
" \n", | |
" if(touch_down == 1 or yardline<= 0 ):\n", | |
" if(opp_drive == 0):\n", | |
" EP[i] += 7\n", | |
" else:\n", | |
" EP[i] -= 7\n", | |
" \n", | |
" break\n", | |
"\n", | |
" \n", | |
" if(down == 5 ):\n", | |
" if(opp_drive == 0):\n", | |
" yardline = max(min(100-int(yardline-yard_gain),99),1)\n", | |
" down = 1\n", | |
" yards_to_go = min(10,yardline)\n", | |
" opp_drive = 1\n", | |
" continue\n", | |
"\n", | |
" else:\n", | |
" break\n", | |
"\n", | |
"\n", | |
" if(safety == 1 or yardline >= 100):\n", | |
" if(opp_drive == 0):\n", | |
" EP[i] -= 2\n", | |
"\n", | |
" else:\n", | |
" EP[i] += 2\n", | |
" break\n", | |
" \n", | |
" \n", | |
" if(no_play == 0):\n", | |
" down += 1\n", | |
" yardline -= yard_gain\n", | |
" yards_to_go -= yard_gain\n", | |
" if(first_down == 1):\n", | |
" down = 1\n", | |
" yards_to_go = min(10,yardline) \n", | |
" if(i % 100 == 0):\n", | |
" print(i)\n", | |
" EP_yardline[j-1] += np.nanmean(EP)" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.5.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment