Skip to content

Instantly share code, notes, and snippets.

@903124
Last active May 27, 2019 17:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 903124/6693fdf6b991437a6d6ef9c5d935c83b to your computer and use it in GitHub Desktop.
Save 903124/6693fdf6b991437a6d6ef9c5d935c83b to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"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