{"cells":[{"metadata":{"toc":true,"_uuid":"83ac24068dbce31c94789975a9b90e6070316b6a"},"cell_type":"markdown","source":"<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\"><span class=\"toc-item-num\">1&nbsp;&nbsp;</span>Introduction</a></span><ul class=\"toc-item\"><li><span><a href=\"#Judging-Criteria\" data-toc-modified-id=\"Judging-Criteria-1.1\"><span class=\"toc-item-num\">1.1&nbsp;&nbsp;</span>Judging Criteria</a></span></li><li><span><a href=\"#Important-readability-notes\" data-toc-modified-id=\"Important-readability-notes-1.2\"><span class=\"toc-item-num\">1.2&nbsp;&nbsp;</span>Important readability notes</a></span></li></ul></li><li><span><a href=\"#Suggested-rule-changes\" data-toc-modified-id=\"Suggested-rule-changes-2\"><span class=\"toc-item-num\">2&nbsp;&nbsp;</span>Suggested rule changes</a></span><ul class=\"toc-item\"><li><span><a href=\"#Rule-1:---15-yard-personal-fouls-for-overly-aggressive-hits-to-a-players-blindside-(side-or-back).\" data-toc-modified-id=\"Rule-1:---15-yard-personal-fouls-for-overly-aggressive-hits-to-a-players-blindside-(side-or-back).-2.1\"><span class=\"toc-item-num\">2.1&nbsp;&nbsp;</span>Rule 1:   15-yard personal fouls for overly-aggressive hits to a players blindside (side or back).</a></span></li><li><span><a href=\"#Rule-2:-15-yard-personal-foul-for-launching-at-defenseless-player.\" data-toc-modified-id=\"Rule-2:-15-yard-personal-foul-for-launching-at-defenseless-player.-2.2\"><span class=\"toc-item-num\">2.2&nbsp;&nbsp;</span>Rule 2: 15-yard personal foul for launching at defenseless player.</a></span></li><li><span><a href=\"#Rule-3:-A-cleanly-fielded-fair-catch-by-the-return-team-will-move-the-line-of-scrimmage-up-5-yards-from-where-the-ball-is-caught.\" data-toc-modified-id=\"Rule-3:-A-cleanly-fielded-fair-catch-by-the-return-team-will-move-the-line-of-scrimmage-up-5-yards-from-where-the-ball-is-caught.-2.3\"><span class=\"toc-item-num\">2.3&nbsp;&nbsp;</span>Rule 3: A cleanly fielded fair catch by the return team will move the line of scrimmage up 5 yards from where the ball is caught.</a></span></li></ul></li><li><span><a href=\"#Data-Preprocessing\" data-toc-modified-id=\"Data-Preprocessing-3\"><span class=\"toc-item-num\">3&nbsp;&nbsp;</span>Data Preprocessing</a></span></li><li><span><a href=\"#Caluclating-blindside-hits-from-NGS\" data-toc-modified-id=\"Caluclating-blindside-hits-from-NGS-4\"><span class=\"toc-item-num\">4&nbsp;&nbsp;</span>Caluclating blindside hits from NGS</a></span></li><li><span><a href=\"#Increased-injury-risk-for-returned-punts\" data-toc-modified-id=\"Increased-injury-risk-for-returned-punts-5\"><span class=\"toc-item-num\">5&nbsp;&nbsp;</span>Increased injury risk for returned punts</a></span></li><li><span><a href=\"#High-risk-factors-within-concussion-plays\" data-toc-modified-id=\"High-risk-factors-within-concussion-plays-6\"><span class=\"toc-item-num\">6&nbsp;&nbsp;</span>High risk factors within concussion plays</a></span></li><li><span><a href=\"#Random-Forest-to-identify-important-features\" data-toc-modified-id=\"Random-Forest-to-identify-important-features-7\"><span class=\"toc-item-num\">7&nbsp;&nbsp;</span>Random Forest to identify important features</a></span></li></ul></div>"},{"metadata":{"_uuid":"9d483f539e54f53fe46b43a86dd35b9a10c0b06f"},"cell_type":"markdown","source":"# Introduction\n\nThe primary goal of the NFL Punt Analytics Competition is to use data analytics to identify risk factors associated with concussions on punt plays, and to suggest new rules which may reduce these risks without affecting the intergrity of the game. \n\nThis team consists of:\nIsaac Perron (ijperron, KaggleID: 1869043)\nCameron Jones (cjones903\n\n\n## Judging Criteria\n\n\n**Solution Efficacy:**\nHave you clearly demonstrated, through your data analysis, that you have an understanding of what play features may be associated with concussions and how your proposed rule change(s) will reduce these injuries? Your kernels should be easy to understand, and the analysis should be reproducible.\n\n**Game Integrity:**\nIs your proposal actionable by the NFL? Could the NFL implement your rule change and still maintain the integrity of the game and the punt play? Have you considered the way your proposed changes to game dynamics could introduce new risks to player safety? Strong submissions will demonstrate an understanding for the game overall.\n\n## Important readability notes\n\n*Terminology*   \n**Injuring player:** the player who causes the injury risk    \n**Injured player:** the player who is injured or is at risk of injury   \n**Gn**: Gunner on return team   \n**V**: Gunner on punting team   \n**LS**: Long snapper   \n**POW**: Offensive line, wing   \n**PDL**: Defensive line   "},{"metadata":{"_uuid":"58c4f857ff02fc054767ba38e6c03dd64b78c327"},"cell_type":"markdown","source":"# Suggested rule changes\n\n## Rule 1:   15-yard personal fouls for overly-aggressive hits to a players blindside (side or back). \n\nWe analyzed NGS to track blindside blocks, finding that 35% of concussions result from these hits. This rule should encourage players to reduce blocking force on legal (side) and illegal (back) blocks.\n\n[Example 1.1](https://nfl-vod.cdn.anvato.net/league/5691/18/11/25/284954/284954_75F12432BA90408C92660A696C1A12C8_181125_284954_huber_punt_3200.mp4)   \n[Example 1.2](http://a.video.nfl.com//films/vodzilla/153234/Punt_by_Kasey_Redfern-w6Cpit4D-20181119_152918853_5000k.mp4)\n\n## Rule 2: 15-yard personal foul for launching at defenseless player.\n\nWhile researching blindside hits, we found instances of technically non-blindside (legal) hits where one player left his feet and launched his body at a defenseless player. This action was not necessary to effectively block his intended target, and should be flagged as unncessary roughness.\n\n[Example 2.1](http://a.video.nfl.com//films/vodzilla/153280/Wing_37_yard_punt-cPHvctKg-20181119_165941654_5000k.mp4)   \n[Example 2.2](http://a.video.nfl.com//films/vodzilla/153258/61_yard_Punt_by_Brett_Kern-g8sqyGTz-20181119_162413664_5000k.mp4)\n\n## Rule 3: A cleanly fielded fair catch by the return team will move the line of scrimmage up 5 yards from where the ball is caught.\n\nWe show that non-returned punts (defined by fair catch, downed, kicked out of bounds, or touchbacks) have 7x reduction in concussion rate compared to returned punts. This rule should incentive returners to fair catch the ball and punters to kick out of bounds, while keeping the integrity of the punting play intact.\n\n[Example 3.1](https://nfl-vod.cdn.anvato.net/league/5691/18/11/25/284956/284956_12D27120C06E4DB994040750FB43991D_181125_284956_way_punt_3200.mp4)   \n[Example 3.2](http://a.video.nfl.com//films/vodzilla/153249/Punt_by_Brett_Kern-KYTnoH51-20181119_161310312_5000k.mp4)\n"},{"metadata":{"_uuid":"a84018aeb854c6317399a2fd91b19c949c5ad8f0"},"cell_type":"markdown","source":"# Data Preprocessing"},{"metadata":{"trusted":true,"_uuid":"79a10f75b40a1fd0af3cfb601e22ea61b928d6d4"},"cell_type":"code","source":"import os\nimport glob\nimport datetime as dt\nimport csv\nimport numpy as np\nimport pandas as pd\nimport seaborn as sn\nimport matplotlib.pyplot as plt\nimport os\nfrom scipy import ndimage, misc\nfrom skimage.transform import resize\nimport pickle\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"66fe5ad1e7519a0ced8c784ea9c8eb69498d82b2"},"cell_type":"code","source":"base_dir = os.path.join(\"../input\")\nall_files = glob.glob(os.path.join(base_dir, \"*.csv\"))\nfor a in list(all_files):\n    print(a)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"90b56ef14d0f2739e1d792e34ffd9a45e3702332"},"cell_type":"code","source":"def consol_pos(x):    \n    if x in ['RB','FB']:\n        return 'HB' #halfback\n    elif x in ['SS','FS']:\n        return 'S' #safety\n    elif x in ['MLB','ILB','OLB']:\n        return 'LB' #linebacker\n    elif x in ['PLT','PRT','PLG','PRG']:\n        return 'POL' #Punt O-line\n    elif x in ['LS','PLS']:\n        return 'LS' #long snapper\n    elif x in ['PLW','PRW']:\n        return 'POW' #Punting offessive-wing (could call them tight ends really)\n    elif x in ['GL','GR','GLi','GRo','GLo','GRi']:\n        return 'Gn' #Gunner on return team\n    elif x in ['VR','VRo','VRi','VL','VLi','VLo']:\n        return 'V' #Gunner on kicking team\n    elif x in ['PDR1','PDR2','PDR3','PDL1','PDL2','PDL3','PDR4','PDL5','PDR6','PDL6','PDR5','PDL4','PDM']:\n        return 'PDL' #PuntD-line\n    elif x in ['PLR','PLM','PLL','PLR2','PLL2','PLM1','PLR3','PLL3','PLL1','PLLi','PLR1']:\n        return 'PLB' #Punt LB\n    elif x in ['PPL','PPR','PPRo','PPRi','PPLo','PPLi','PC']:\n        return 'PP' #Punting backfield \n    else:\n        return x\n    \n# Defines whether on kicking or return team\ndef kick_ret(x):\n    if x in ['P','PP','LS','POW','POL','Gn']:\n        return 'KICK'\n    elif x in ['PDL','PLB','V','PR','PFB']:\n        return 'RET'\n    else:\n        return 'UNKN'\n\ninj = pd.read_csv(os.path.join(base_dir, \"video_review.csv\"))\ninj['concussion'] = 1\n\nppd = pd.read_csv(os.path.join(base_dir, \"player_punt_data.csv\"))\nppd = ppd[ppd.GSISID.isin(list(inj.GSISID.unique()))][['GSISID','Position']]\\\n        .sort_values('GSISID').drop_duplicates().reset_index(drop=True)\nppd['Position_consol'] = ppd.Position.apply(lambda x: consol_pos(x))\n\npprd = pd.read_csv(os.path.join(base_dir, \"play_player_role_data.csv\"))\npprd['Role_consol'] = pprd.Role.apply(lambda x: consol_pos(x))\npprd['Kick_ret'] = pprd.Role_consol.apply(lambda x: kick_ret(x))\n\ninj = inj.merge(ppd[['GSISID','Position','Position_consol']],on='GSISID',how='inner')\ninj = inj.merge(pprd,on=['Season_Year','GameKey','PlayID','GSISID'])\n\ndisplay(inj.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7a88f8e288a19190fd280324e34e44646521afa4"},"cell_type":"code","source":"def intl_cities(x):\n    if x in ['Wembley','Twickenham','London']:\n        return 'UK'\n    elif x in ['Mexico','Mexico City']:\n        return 'MEX'\n    else:\n        return 'USA'\n\ndef stadium_type(x):\n    if x in ['Outdoor','Outdoors','outdoor','Outside','Outdoors ','Ourdoor','Outddors','Oudoor','Outdor',\n             'Heinz Field','Turf']:\n        return 'outdoor'\n    elif x in ['Dome','Indoor','non-retractable roof','Retr. Roof - Closed','Indoors','Indoor',\n               'Indoor, Non-Retractable Dome','Retr. Roof-Closed','Retr. roof - closed','Indoor, fixed roof',\n              'Indoor, Fixed Roof','Indoors (Domed)','Domed, closed','Indoor, Roof Closed','Retr. Roof Closed',\n              'Closed Dome','Dome, closed','Indoor, non-retractable roof']:\n        return 'indoor_closed'\n    elif x in ['Retractable Roof','Open','Retr. Roof-Open','Retr. Roof - Open','Indoor, Open Roof',\n               'Outdoor Retr Roof-Open']:\n        return 'indoor_open'\n    elif np.isnan(x):\n        return 'outdoor'\n    else:\n        return x\n    \ndef turf_type(x):\n    if x in ['Turf','Artificial','Synthetic','Artifical']:\n        return 'Generic_turf'\n    elif x in ['Grass','Natural Grass', 'Natural grass','Natural Grass ','Natural','Natrual Grass','Naturall Grass',]:\n        return 'Grass'\n    elif x in ['DD GrassMaster']:\n        return 'Grassmaster'\n    elif x in ['A-Turf Titan']:\n        return 'A-Turf_titan'\n    elif x in ['FieldTurf','Field Turf','FieldTurf 360','FieldTurf360','Field turf']:\n        return 'Fieldturf'\n    elif x in ['UBU Speed Series-S5-M','UBU Sports Speed S5-M','UBU Speed Series S5-M']:\n        return 'UBU_speed_series_S5-M'\n    elif x in ['AstroTurf GameDay Grass 3D']:\n        return 'Astroturf'\n    elif pd.isna(x):\n        return 'Grass'\n    else:\n        return x\n        \ngi = pd.read_csv(os.path.join(base_dir, \"game_data.csv\"))\n\ngi['Start_time_hour'] = gi.Start_Time.apply(lambda x: x[:2])\ngi['StadiumType_consol'] = gi.StadiumType.apply(lambda x: stadium_type(x))\ngi['intl_cities'] = gi.Game_Site.apply(lambda x: intl_cities(x))\ngi['Turf_consol'] = gi.Turf.apply(lambda x: turf_type(x))\ngi['is_sunny'] = gi.GameWeather.apply(lambda x: 1 if any(ss in str(x).lower() for ss in ['sun','part']) else 0)\ngi['is_cloudy'] = gi.GameWeather.apply(lambda x: 1 if any(ss in str(x).lower() for ss in ['cloud','part']) else 0)\ngi['is_clear'] = gi.GameWeather.apply(lambda x: 1 if any(ss in str(x).lower() for ss in ['clear']) else 0)\ngi['is_rain'] = gi.GameWeather.apply(lambda x: 1 if any(ss in str(x).lower() for ss in ['rain','storm']) else 0)\ngi['is_snow'] = gi.GameWeather.apply(lambda x: 1 if any(ss in str(x).lower() for ss in ['snow']) else 0)\n\ngi_merge = gi[['GameKey','Season_Year','Season_Type','Week','Game_Day','Game_Site','Start_time_hour',\n              'StadiumType_consol','intl_cities','Turf_consol','is_sunny','is_cloudy','is_clear','is_rain','is_snow']]\n\ndisplay(gi_merge.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bd87b7c8872491660b4ba31159a72b38220d6f84"},"cell_type":"code","source":"def get_half(x):\n    if x in [1,2]:\n        return 1\n    elif x in [3,4]:\n        return 2\n    elif x == 5:\n        return 3\n    \ndef get_penalty_type(PlayDescription):\n    '''Extract Penalty Types From Text'''\n    PlayDescription = PlayDescription.upper()\n    try:\n        enum_object = list(enumerate(PlayDescription.split(',')))\n        penalty_obj = [x for x,y in enum_object if 'PENALTY' in y]\n        return enum_object[penalty_obj[0]+1][1]\n    except:\n        return 'None'\n\npi = pd.read_csv(os.path.join(base_dir, \"play_information.csv\"))\npi.head()\n\npi['half'] = pi.Quarter.apply(lambda x: get_half(x))\npi['late_quart'] = [0 if x in [1,3,5] else 1 for x in pi.Quarter]\ngc = pi.Game_Clock.str.split(\":\").apply(pd.Series)\npi['sec_elapsed_quart'] = (60*(14 - gc[0].astype(int)) + (60 - gc[1].astype(int)))\npi['sec_elapsed_half'] = (900*pi.late_quart) + pi.sec_elapsed_quart\n\npi['punt_in_own_terr'] = pi.apply(lambda x: x.Poss_Team != x.YardLine.split(' ')[0],axis=1).astype(int)\npi['yards_from_own_endzone'] = pi.apply(lambda x: x.punt_in_own_terr*(100-int(x.YardLine.split(' ')[1])) + \n         (1-x.punt_in_own_terr)*(int(x.YardLine.split(' ')[1])),axis=1)\n\npi['is_muff'] = pi.PlayDescription.str.contains('MUFF',case=False).astype(int)\npi['is_penalty'] = pi.PlayDescription.str.contains('PENALTY',case=False).astype(int)\npi['is_faircatch'] = pi.PlayDescription.str.contains('FAIR',case=False).astype(int)\npi['penalty_type'] = pi.PlayDescription.apply(get_penalty_type)\npi['is_touchback'] = pi.PlayDescription.str.contains('TOUCHBACK',case=False).astype(int)\npi['is_oob'] = pi.PlayDescription.str.contains('OUT OF BOUNDS',case=False).astype(int)\npi['is_downed'] = pi.PlayDescription.str.contains('DOWNED',case=False).astype(int)\npi['is_returned'] = pi.apply(lambda x: x[['is_faircatch','is_downed','is_oob','is_touchback']].any() != 1,axis=1).astype(int)\n\nscore_diff = pi.Score_Home_Visiting.str.split(' - ').apply(pd.Series).astype(int)\npi['sd'] = score_diff[0] - score_diff[1]\npi['home_team'] = (pi.Home_Team_Visit_Team.str.split('-').apply(pd.Series))[0]\npi['is_home_team_punting'] = (pi.home_team == pi.Poss_Team).astype(int).replace(0,-1)\npi['score_diff'] = pi.sd * pi.is_home_team_punting\n\n\npi_merge = pi[['Season_Year','Season_Type','GameKey','Week','PlayID','sec_elapsed_half','half',\n               'yards_from_own_endzone','is_muff','is_penalty','is_oob','is_returned','is_faircatch','penalty_type',\n              'score_diff']]\n\ndisplay(pi_merge.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8dfee26c6bb1e0c66348d124350ae05bb48dc979"},"cell_type":"code","source":"merge_data = pd.merge(pi_merge, inj[['GameKey','PlayID','concussion']],on=['GameKey','PlayID'],how='outer').fillna(0)\nmerge_data = gi_merge.merge(merge_data,left_on=['Season_Year','GameKey'],right_on=['Season_Year','GameKey']).set_index(['Season_Year','GameKey','PlayID'])\nmerge_data = merge_data.drop(['Week_y','Season_Type_y'],axis=1).rename(mapper = {'Week_x':'Week','Season_Type_x':'Season_Type'},axis=1)\n\ndisplay(merge_data.head())\ndisplay(merge_data.shape)\ndisplay(merge_data.columns)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a9ff866dcf298e57c55ebbbb44848a51e21feff6"},"cell_type":"markdown","source":"# Caluclating blindside hits from NGS"},{"metadata":{"trusted":true,"_uuid":"4fe4adeda8c1e1f258973f9409c592d78a5ea690"},"cell_type":"code","source":"game_file_dict = dict()\n\ndef make_game_dicts():\n     for file in ['NGS-2016-pre.csv','NGS-2016-reg-wk7-12.csv','NGS-2017-reg-wk7-12.csv','NGS-2017-pre.csv',\n              'NGS-2016-reg-wk1-6.csv','NGS-2016-post.csv','NGS-2017-post.csv','NGS-2016-reg-wk13-17.csv',\n              'NGS-2017-reg-wk1-6.csv','NGS-2017-reg-wk13-17.csv']:\n        game_data = pd.read_csv(os.path.join(base_dir, file))\n        game_data['season'] = file\n        season_dict = game_data.set_index(['Season_Year','GameKey'])['season'].to_dict()\n        game_file_dict.update(season_dict)\n        \nmake_game_dicts()\n\ndef find_intersection_angle(row):\n    finder = FindTheBoom(int_data,NGSTable=pre_2016,gamekey=row.GameKey,playid=row.PlayID)\n    p1,p2 = finder.find_partners()\n    coords = finder.find_coords(py1 = p1, py2 = p2)\n    moment_of_intersection = finder.find_moment_of_intersection(coords)\n    angle = finder.find_blindness(coords=coords,moment=moment_of_intersection)\n    return angle","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"65a75a69035596efa06aacb6812d89a659635b70"},"cell_type":"code","source":"#Find the blindside hit\nclass FindTheBoom:\n    \n    def __init__(self, InteractionTable,gamekey,playid,seasonyear):\n        self.itable = InteractionTable\n        self.gk = gamekey\n        self.pid = playid\n        self.season = seasonyear\n    \n    def find_game_file(self,seasonyear, gamekey):\n        file = game_file_dict[(seasonyear,gamekey)]\n        df = pd.read_csv('../input/'+file)\n        return df\n        \n    def find_partners(self):\n        temp_table = self.itable[(self.itable.GameKey == self.gk) & (self.itable.PlayID == self.pid)]\n        return temp_table.GSISID.values.astype(int), temp_table.Primary_Partner_GSISID.values.astype(int)\n    \n    def find_coords(self,py1,py2):\n        ngs_table = self.find_game_file(self.season,self.gk)\n        print(ngs_table)\n        p1 = ngs_table[(ngs_table.GameKey == self.gk) & (ngs_table.PlayID == self.pid) & (ngs_table.GSISID == py1[0])].sort_values('Time')[['Time','x','y','o','dir']].set_index('Time')\n        p2 = ngs_table[(ngs_table.GameKey == self.gk) & (ngs_table.PlayID == self.pid) & (ngs_table.GSISID == py2[0])].sort_values('Time')[['Time','x','y','o','dir']].set_index('Time')\n        return pd.merge(p1,p2,left_index=True,right_index=True,suffixes=['p1','p2'])\n    \n    def find_moment_of_intersection(self,df):\n        df['distance'] = df.apply(lambda x: np.sqrt(abs(x.xp1-x.xp2) + abs(x.yp1 - x.yp2)),axis=1)\n        return df.distance.idxmin()\n    \n    ## Looking at the injuring players body vs injured players head\n    def find_blindness(self, coords,moment):\n        impact = coords.loc[moment]\n        return (impact.op1 - impact.dirp2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9490bc45da5d7172a9493d8c93a314239e1ea85a"},"cell_type":"code","source":"result_frame = pd.DataFrame(columns=['Season_Year','GameKey','PlayID','Angle'])\nfor i in inj.iterrows():\n    try:\n        finder = FindTheBoom(inj,gamekey=i[1].GameKey,playid=i[1].PlayID,seasonyear=i[1].Season_Year)\n        p1,p2 = finder.find_partners()\n        coords = finder.find_coords(py1 = p1, py2 = p2)\n        print(coords)\n        moment_of_intersection = finder.find_moment_of_intersection(coords)\n        angle = finder.find_blindness(coords=coords,moment=moment_of_intersection)\n        result_frame = result_frame.append({'Season_Year':i[1].Season_Year,'GameKey':i[1].GameKey,\n                                            'PlayID':i[1].PlayID,'Angle':angle},ignore_index=True)\n    except:\n        result_frame = result_frame.append({'Season_Year':i[1].Season_Year,'GameKey':i[1].GameKey,\n                                            'PlayID':i[1].PlayID,'Angle':None},ignore_index=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d9c6442d070f17fc776838453c1cb6486434eb8e"},"cell_type":"code","source":"result_frame","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"69e5a3855a6eee2acb161e4f43d7f966856543cf"},"cell_type":"code","source":"injb = inj.copy()\ninjb = injb.merge(result_frame, on =['Season_Year','GameKey','PlayID'])\ninjb['is_blindside'] = injb.Angle.apply(lambda x: 1 if abs(x) < 120 else 0)\ninjb.is_blindside.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a4fb1db3c6adc76e2da088938fec3cc06428936b"},"cell_type":"markdown","source":"# Increased injury risk for returned punts\n\nNon-returned punts have a much lower injury risk (~7x reduction) compared to returned punts.\n\nMuffed punts trend towards a higher concussion risk, but the uncertainty is too great to make any conclusions."},{"metadata":{"trusted":false,"_uuid":"0395aa627f0ec0758752a42d0508d935c54456ad"},"cell_type":"code","source":"plt.figure(figsize=(16, 16))\nsn.set(context='paper')\nsn.catplot(x='is_returned',y='concussion',data=merge_data, kind='point')\nplt.ylabel('Concussion Rate')\nplt.xlabel('Is Returned')\nplt.xticks([0,1],['False','True'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"3e6c563edf4b41581688e5028e7c8399177ea398"},"cell_type":"code","source":"display(pd.crosstab(merge_data.concussion,merge_data.is_returned))\ndisplay(pd.crosstab(merge_data.concussion,merge_data.is_returned,normalize='columns'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"46f360884d00c254e961e981a7a5761e409ece39"},"cell_type":"code","source":"plt.figure(figsize=(16, 16))\nsn.set(context='paper')\nsn.catplot(x='is_muff',y='concussion',data=merge_data, kind='point')\nplt.ylabel('Concussion Rate')\nplt.xlabel('Is Muff')\nplt.xticks([0,1],['False','True'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"33add90399eb31df1642fe40b62aff4896fbd461"},"cell_type":"markdown","source":"# High risk factors within concussion plays\n\nOffensive linemen are at highest risk for concussion.\nMembers of the kicking team compose of 78% of all concussions (in the availale data set)."},{"metadata":{"trusted":false,"_uuid":"a045ac323d707b86a361f6fae27fefa79d923d49"},"cell_type":"code","source":"inj.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"3ee9db819579670feda24fb073815e4bc514dd16"},"cell_type":"code","source":"pd.DataFrame(inj.Role_consol.value_counts(normalize=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"eb3e625ad05649360a78bb504c6f8a0805f599e1"},"cell_type":"code","source":"pd.DataFrame(inj.Kick_ret.value_counts(normalize=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"7e9bfec692469f43e486cad91080601303dbc262"},"cell_type":"code","source":"pd.DataFrame(inj.Position_consol.value_counts(normalize=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"9bf1ab004d5f07b69258a3b90aca4df72a2d4985"},"cell_type":"code","source":"pd.DataFrame(inj.Primary_Impact_Type.value_counts(normalize=True))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"c99c14129b6bcaa63d4751fc7ea62da203309251"},"cell_type":"code","source":"pd.crosstab(inj.Player_Activity_Derived,inj.Primary_Partner_Activity_Derived)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8879f1091f1c383da37df4a83f7b66c7ed5416be"},"cell_type":"markdown","source":"# Random Forest to identify important features\n\nThere were a few suprises, mainly that the yards from the endzone, the score differential, and the seconds elapsed in the half were identified as important features.\n\nHowever, upon closer inspection:   \n1) The yards from the endzone can be explained by longer, booming kicks which have a higher likelihood of being returned.    \n2) There was too much variability in the 'score differential' and 'seconds elapsed in the half' associations to draw any conclcusions. "},{"metadata":{"trusted":false,"_uuid":"9521e5339e5fda7e6253bf4b5a3637f253eaf977"},"cell_type":"code","source":"OHE_cols = ['Season_Type','Game_Day','Game_Site','StadiumType_consol','intl_cities','Turf_consol','penalty_type']\nOHE = pd.get_dummies(merge_data[OHE_cols])\nother_cols = [col for col in merge_data.columns if col not in OHE_cols]\nnot_OHE = merge_data[other_cols]\n\ncoded_data = not_OHE.merge(OHE,left_index=True,right_index=True)\ndisplay(coded_data.columns)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"f9616947f9d652464463c94035bd248d99f003bd"},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\n\ny = coded_data.concussion\nX = coded_data.drop('concussion',axis=1)\n\nX_train, X_test, y_train, y_test = train_test_split(X,y,test_size=.2,stratify=y)\nrfc = RandomForestClassifier(n_estimators=3000,class_weight='balanced')\nrfc.fit(X=X_train,y=y_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"cf18298cb29fc1bc7ffddc5e5e141f6acbc70082"},"cell_type":"code","source":"feat_imp = pd.DataFrame(list(zip(X_train.columns,rfc.feature_importances_)),columns=['feat','imp'])\nfeat_imp = feat_imp.set_index('feat')\ndisplay(feat_imp.sort_values('imp',ascending=False))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"f4558c7b8791ff869b1b9002018bbbae728fb8d5"},"cell_type":"code","source":"coded_data[coded_data.concussion==1].score_diff.plot(kind='hist',density=True,label='concussion',alpha=.5)\ncoded_data[coded_data.concussion==0].score_diff.plot(kind='hist',density=True,label='no_concussion',alpha=.5)\nplt.xlabel('score differential')\nplt.legend()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"c7bc20e6d926dd6ab6e7cf13a7f29c0c74005120"},"cell_type":"code","source":"coded_data[coded_data.concussion==1].yards_from_own_endzone.plot(kind='hist',density=True,label='concussion',alpha=.5)\ncoded_data[coded_data.concussion==0].yards_from_own_endzone.plot(kind='hist',density=True,label='no_concussion',alpha=.5)\nplt.xlabel('yards from own endzone')\nplt.legend()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"4b85dd285e71bc598b3601f8a95bee2b41a494cf"},"cell_type":"code","source":"plt.rcParams['figure.figsize'] = (20,20)\nsn.factorplot(y='yards_from_own_endzone',x='is_returned',data=coded_data,ci=95)\nplt.xlabel('Is Returned')\nplt.ylabel('Yards from own endzone')\nplt.xticks([0,1],['False','True'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"1a08845ebaf0be4cdd04364496f16ea134623258"},"cell_type":"code","source":"plt.rcParams['figure.figsize'] = (20,20)\nsn.factorplot(y='score_diff',x='concussion',data=coded_data,ci=95)\nplt.xlabel('Is Concussion')\nplt.ylabel('Score differntial')\nplt.xticks([0,1],['False','True'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"51d209d517c8c776bb1b428e1cdfe8f4d37af4b0"},"cell_type":"code","source":"plt.rcParams['figure.figsize'] = (20,20)\nsn.factorplot(y='sec_elapsed_half',x='concussion',data=coded_data,ci=95)\nplt.xlabel('Is Concussion')\nplt.ylabel('Seconds elapsed in the half')\nplt.xticks([0,1],['False','True'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"651aa322029bc235ca35fe57dabf90d0ab09d62f"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"toc":{"nav_menu":{},"number_sections":true,"sideBar":true,"skip_h1_title":false,"title_cell":"Table of Contents","title_sidebar":"Contents","toc_cell":true,"toc_position":{},"toc_section_display":true,"toc_window_display":false}},"nbformat":4,"nbformat_minor":1}