{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":false},"cell_type":"code","source":"\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n\nimport os\nprint(os.listdir(\"../input\"))\npd.set_option('display.max_rows', 500)\npd.set_option('display.max_columns', 500)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":false},"cell_type":"markdown","source":"From 2016-2017 there were 37  concussion related injuries during punt plays alone. My aim in this kernal is demonstrate my proposals to make the punt play not only safer, but more competitive.\n\n* My first proposal would require that the outside gunners to wait until the ball is kicked to run down field \n\n* Second, would be to award 10 yards to the recieving team if a fair catch is taken.\n"},{"metadata":{"trusted":true,"_uuid":"5021b9ae964a4917c4333338f0c40bee636bf616","_kg_hide-input":true},"cell_type":"code","source":"import dask.dataframe as dd\nfrom pandas_summary import DataFrameSummary\nfrom IPython.display import display\nimport statsmodels.api as sm\nfrom sklearn import preprocessing","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ca816657fad66c240d8480134ac897d700714bc4","_kg_hide-input":true},"cell_type":"code","source":"# Read play data\nngs = pd.read_csv('../input/NGS-2016-pre.csv')\nngs.columns = [col.lower() for col in ngs.columns]\n\npprd = pd.read_csv('../input/play_player_role_data.csv')\npprd.columns = [col.lower() for col in pprd.columns]\n\nvr = pd.read_csv('../input/video_review.csv')\nvr.columns = [col.lower() for col in vr.columns]\n\nngs2017pre = pd.read_csv('../input/NGS-2017-pre.csv')\nngs2017pre.columns = [col.lower() for col in ngs2017pre.columns]\n\nvideo_injury = pd.read_csv('../input/video_footage-injury.csv')\nvideo_injury.columns = [col.lower() for col in video_injury.columns]\n\nplay_player_role_data = pd.read_csv('../input/play_player_role_data.csv', low_memory=False)\nplay_player_role_data.columns = [col.lower() for col in play_player_role_data.columns]\n\nplay_info = pd.read_csv('../input/play_information.csv', low_memory=False)\nplay_info.columns = [col.lower() for col in play_info.columns]","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"300c7cac956a3c708fdec97eac569fb9c50f599b"},"cell_type":"code","source":"import re\ndef get_return_yards(s):\n    m = re.search('for ([0-9]+) yards', s)\n    if m:\n        return int(m.group(1))\n    elif re.search('for no gain', s):\n        return 0\n    else:\n        return np.nan\n\nplay_info['return_yards'] = play_info['playdescription'].map(\n        lambda x: get_return_yards(x))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ddca2de2c9f31064e99ffa81aa936f2cf1587639","_kg_hide-input":true},"cell_type":"code","source":"ngs_2016reg_part1 = pd.read_csv('../input/NGS-2016-reg-wk1-6.csv', low_memory=False)\nngs_2016reg_part1.columns = [col.lower() for col in ngs_2016reg_part1.columns]\n\nngs_2016reg_part2 = pd.read_csv('../input/NGS-2016-reg-wk7-12.csv', low_memory=False)\nngs_2016reg_part2.columns = [col.lower() for col in ngs_2016reg_part2.columns]\n\nngs_2016reg_part3 = pd.read_csv('../input/NGS-2016-reg-wk13-17.csv', low_memory=False)\nngs_2016reg_part3.columns = [col.lower() for col in ngs_2016reg_part3.columns]\n\nngs_2017reg_part1 = pd.read_csv('../input/NGS-2017-reg-wk1-6.csv', low_memory=False)\nngs_2017reg_part1.columns = [col.lower() for col in ngs_2017reg_part1.columns]\n\nngs_2017reg_part2 = pd.read_csv('../input/NGS-2017-reg-wk7-12.csv', low_memory=False)\nngs_2017reg_part2.columns = [col.lower() for col in ngs_2017reg_part2.columns]\n\nngs_2017reg_part3 = pd.read_csv('../input/NGS-2017-reg-wk13-17.csv', low_memory=False)\nngs_2017reg_part3.columns = [col.lower() for col in ngs_2017reg_part3.columns]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d1d1cf2491492ba6c671cb618fb89da79f9c16df","_kg_hide-input":true},"cell_type":"code","source":"formation = pd.DataFrame()\nresult_of_punt_df = pd.DataFrame()\ntop_velocity = pd.DataFrame()\nfor i in range(len(vr.index)):\n    \n    game_details = vr[['season_year','gamekey','playid']].sort_values(['season_year','gamekey','playid']).loc[i]\n    season_year = game_details.season_year\n    gamekey = game_details.gamekey\n    playid = game_details.playid\n    \n    season_dfs = [ngs2017pre, ngs, ngs_2016reg_part1, ngs_2016reg_part2, ngs_2016reg_part3, ngs_2017reg_part1,\n                 ngs_2017reg_part2, ngs_2017reg_part3]\n\n    for i in season_dfs:\n\n        play = i[(i['season_year'] == season_year) &\n               (i['gamekey'] == gamekey) &\n               (i['playid'] == playid)]\n        \n\n\n        if len(play.index) != 0:\n            ngs_with_roles = pd.merge(play, pprd)\n            features_df = ngs_with_roles.drop(['season_year'], axis=1).pivot(index='time',\n                                                                columns='role',\n                                                                values=['x', 'y', 'dis', 'event', 'o', 'dir',  'gamekey', 'playid'])\n            \n            # Collect Roles and append them to the formation list\n            formation = formation.append(pd.Series(features_df.x.columns))\n                                    \n            result_of_punt_df = result_of_punt_df.append(\n                pd.DataFrame(features_df.event.GL.loc[(features_df.event['PR']=='punt_received') |\n                                                    (features_df.event['PR']=='punt_downed') |\n                                                    (features_df.event['PR']=='fair_catch') |\n                                                    (features_df.event['PR']=='fumble_offense_recovered')]))\n            \n            for i in features_df.x.columns:\n                features_df.loc[:,('velocity',i)] = features_df.dis[i] / 1.094 / 0.1 * 2.237 #mph\n                \n                \n            max_velocity = pd.concat([features_df.velocity, features_df.gamekey.GL.rename('gamekey'), features_df.playid.GL.rename('playid')],axis=1, sort=False)\n\n            max_velocity['game_play_id'] = max_velocity.gamekey.astype(str) + '_' + max_velocity.playid.astype(str)\n            max_velocity = max_velocity.reset_index().drop(['time', 'playid', 'gamekey'],axis=1)\n            max_velocity = max_velocity.groupby('game_play_id').max()\n            \n            top_velocity = top_velocity.append(max_velocity, sort=True)\n\n","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"489718cb2b682efb56d18f4e8d086b765d02a20f"},"cell_type":"code","source":"play_player_role_data['game_play_id'] = play_player_role_data['gamekey'].astype(str) + '_' + play_player_role_data['playid'].astype(str)\nplay_player_role_data = play_player_role_data.sort_values('role')\n\nplay_info['game_play_id'] = play_info.gamekey.astype(str) + '_' + play_info.playid.astype(str)\nvr['game_play_id'] = vr.gamekey.astype(str) + '_' + vr.playid.astype(str)\nvideo_injury['game_play_id'] = video_injury.gamekey.astype(str) + '_' + video_injury.playid.astype(str)\n\nplay_formations = pd.DataFrame({'formation' :play_player_role_data.groupby('game_play_id').apply(lambda x: '_'.join(x['role']))})\nplay_formations = play_formations.reset_index()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"0a5e60752e4e226478cbae1fe11aa6906ae39fce"},"cell_type":"code","source":"injured_player_role = pd.merge(play_player_role_data, vr, left_on=['gsisid', 'gamekey', 'season_year', 'playid', 'game_play_id'], \n                               right_on=['gsisid', 'gamekey', 'season_year', 'playid', 'game_play_id'], how='inner')\ninjured_player_role[['primary_partner_gsisid']] = injured_player_role[['primary_partner_gsisid']].fillna(0).replace('Unclear', 1).astype(int)\nprimary_partner = play_player_role_data.drop(['season_year', 'gamekey', 'playid'], axis=1)\ninjured_player_role = pd.merge(injured_player_role, primary_partner,\n                               left_on=['primary_partner_gsisid', 'game_play_id'],\n                               right_on=['gsisid', 'game_play_id'], how='left')\n\ninjured_player_role =injured_player_role.drop(['gsisid_y'], axis=1)\ninjured_player_role = injured_player_role.rename(columns={'role_x': 'injury_role', 'role_y': 'primary_partner_role', 'gsisid_x': 'gsisid'})\n\ninjured_player_role.sort_values('gamekey', ascending=True);","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"5a78ceed40c71de668f536785faf9ab3ae04c2cd"},"cell_type":"code","source":"all_punt_data = pd.merge(play_info, play_formations, how='outer', on='game_play_id')\nall_punt_data = pd.merge(all_punt_data, top_velocity, how='inner', on='game_play_id')\nall_punt_data = pd.merge(all_punt_data, vr, how='inner', on=['game_play_id', 'season_year', 'gamekey', 'playid'])\nall_punt_data = pd.merge(all_punt_data, video_injury, how='left', on=['game_play_id', 'gamekey', 'playid', 'week', 'playdescription']).drop('quarter', axis=1)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"af6e5aa89d2f6e95bd68e5c5e65aa9cd8ce8662b"},"cell_type":"code","source":"all_punt_data[['primary_partner_gsisid']] = all_punt_data[['primary_partner_gsisid']].fillna(0).replace('Unclear', 1).astype(int)\nall_punt_data = pd.merge(all_punt_data, injured_player_role, how='inner', \n                         left_on=['season_year', 'gamekey', 'playid', 'game_play_id', 'gsisid', 'player_activity_derived', 'turnover_related', \n                                  'primary_impact_type', 'primary_partner_gsisid', 'primary_partner_activity_derived', 'friendly_fire'],\n                         right_on=['season_year', 'gamekey', 'playid', 'game_play_id', 'gsisid', 'player_activity_derived', 'turnover_related', \n                                  'primary_impact_type', 'primary_partner_gsisid', 'primary_partner_activity_derived', 'friendly_fire'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"741c39e7ba754e8f0c37126032ea774e72ee60df"},"cell_type":"markdown","source":"Let's examine historical plays to find trends and insights into why certain plays result in concussions.\n\nWe can see in 80% of plays which result in a concussion, the highest chance is when the punt is received. This is more than likely due to the impacts that come along with trying to tackle the ball carrier versus a fair catch where the play is over wherever it is caught."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"5444074a638a17a79dff22dcd6eda55efeccd947"},"cell_type":"code","source":"result_of_punt_df.GL.value_counts().plot(kind='bar', title='Punt Results')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3cfca60087f8e52d5d8251664019edf0a3330502"},"cell_type":"markdown","source":"Let's dive a little deeper into who is receiving and who is causing those injuries. The chart below shows that most of the injuries are to the players who are typically first to the ball or receiving the ball. The primary partners, who are the ones delivering the impact, seem to come from the linemen with the exepction of the punt returner."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"6fa8f2728a226c29a73fb30932ff0022081bdee8"},"cell_type":"code","source":"injured_player_role.injury_role.value_counts().plot(kind='bar', title='Role of Concussed')","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"a14417fcf510834e38e34656420804c618d22c0a"},"cell_type":"code","source":"injured_player_role.primary_partner_role.value_counts().plot(kind='bar', title='Role of Primary Partner')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2340a557919ee902f35516c56df23190752725f8"},"cell_type":"markdown","source":"When comparing the balance of injuries, we can see the the kicking team is 76% more likely to receive an injury than the kicking team"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"7c681e69156a08e8dccd9b10e05560c082b277c9"},"cell_type":"code","source":"receiving_position = ['PR', 'PFB', 'VR', 'PDR1', 'PDL2']\n\nrecieving_team = all_punt_data[all_punt_data.injury_role.isin(receiving_position)]\npd.value_counts(recieving_team['injury_role']).plot(kind='bar', title='Concussed data by receiving team position')","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"8bbd1ce568050830862172490f4d13d45f0f2d69"},"cell_type":"code","source":"kicking_team = all_punt_data[~ all_punt_data.injury_role.isin(receiving_position)]\npd.value_counts(kicking_team['injury_role']).plot(kind='bar', title='Concussed data by punting team position')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b8a2c19a6d3e0402a031727c15ca07d6f01b9590"},"cell_type":"markdown","source":"As we go forward, we should look into what the activity of the injured player was before the injury. From our chart below, we can see the most frequent activity was tackling. However, it is an equal balance between tackling and blocking for the primary partner."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"0f82a73610fe9c3bd4d77bbe025c79385531521d"},"cell_type":"code","source":"injured_player_role.player_activity_derived.value_counts().plot(kind='bar', title='Activity of Player Before Injury')","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"a28bf7eff8684a3c66ef148f2e3e930328e121d7"},"cell_type":"code","source":"injured_player_role.primary_partner_activity_derived.value_counts().plot(kind='bar', title='Activity of Primary Partner Before Injury')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bb2fd45f33bf9932caa907cbba6e6345fa35f093"},"cell_type":"markdown","source":"As we drill down, we can see the most frequent impacts are a result of helmet to body and helmet to helmet. \n\nA note that the NFL has outlawed avoidable helmet to helmet contact so if we had the data from the 2018 season, I believe this chart would look very different."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"04a18ed10c61635fc3d61800a0257a238fe66237"},"cell_type":"code","source":"impact_type =  injured_player_role.primary_impact_type.value_counts().plot(kind='bar', title='Primary Impact')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fb2933d03f0fd51f73f8c9d81de2ba7156942d21"},"cell_type":"markdown","source":"Now that we have analysed some of the overall data, I will demonstrate why I believe the NFL should adopt a rule requiring that the outside gunners to wait untill the ball is kicked, to run down field. \n\nIn the current rules, the gunners are the only players allowed to pass the line of scrimmage before the punter has kicked the ball. This is dangerous becasuse with an average hang time of 4.5 seconds on a punt, this allows the gunners to cover roughly 40 yards in that amount of time plus the approximately 2 seconds it takes to snap the ball and kick it. This leads to gunners being almost ready to crash into the punt returner, if not run past him, at full speed. The punt returner can avert this impact by calling for a fair catch or letting the ball bounce but it doesn't give them a chance to return the ball. With my proposed rule change, this would give punt returners a chance to return the ball which would make the play more competitive but also lower the closing velocity of the gunners.\n"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"2ef497e3f2512211997459ecb448089b9c8c43c4"},"cell_type":"code","source":"def get_hang_time(ngs_df, start_event='punt', *stop_events):\n    punt_event = ngs_df.loc[ngs_df.event==start_event] \\\n        .groupby(['season_year', 'gamekey','playid'], as_index = False)['time'].min()\n    punt_event.rename(columns = {'time':'punt_time'}, inplace=True)\n    punt_event['punt_time'] = pd.to_datetime(punt_event['punt_time'],\\\n                                             format='%Y-%m-%d %H:%M:%S.%f')\n    \n    receiving_event = ngs_df.loc[ngs_df.event.isin(stop_events)] \\\n        .groupby(['season_year', 'gamekey','playid'], as_index = False)['time'].min()\n    receiving_event.rename(columns = {'time':'receiving_time'}, inplace=True)\n    receiving_event['receiving_time'] = pd.to_datetime(receiving_event['receiving_time'],\\\n                                             format='%Y-%m-%d %H:%M:%S.%f')\n    \n    punt_df = punt_event.merge(receiving_event, how='inner', on = ['season_year', 'gamekey','playid']) \\\n                .reset_index(drop=True)\n    \n    punt_df['hang_time'] = (punt_df['receiving_time'] - punt_df['punt_time']).dt.total_seconds()\n    \n    return punt_df\npunt_df = get_hang_time(ngs_2016reg_part1, 'punt', 'punt_received', 'fair_catch')\nprint('The average hang time is {} seconds' .format(round(punt_df['hang_time'].mean(), 1)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1af6ca39beefae61c4f16c9d214ceecf08be9c1b","_kg_hide-input":true},"cell_type":"code","source":"punt_df.hang_time.hist()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"19bf6a3293785da2630c880d1a80645b1592da9e"},"cell_type":"markdown","source":"Finally, I would like to provide an example of why I believe the NFL should adopt a new rule to award 10 yards if a fair catch is called. Below is a graph of how many yards were gained off of punt returns. The vast majority of punts were returned for a maximum total of 9.5 yards or less. This is almost 56% of all punts. On punts without a lot of open field position, the gunners typically have more than enough time to get down field to be feet away from the returner and hit them at a dangerously high velocity. With this new rule, players are incentivized to call a fair catch and get more yardage than they otherwise would have under the old rules. However, if the returner saw a path to getting more than 10 yards, they would still be eligible to do so."},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":false,"trusted":true,"_uuid":"e86c5d71bfaef5566ecfff19f1f0c40667d792e1"},"cell_type":"code","source":"return_yards = play_info.return_yards.value_counts(ascending=True, bins=10)\nreturn_yards.plot('bar', title='Yards Gained on Punts')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bd338079ccd7345548a370ae9ae8c38882a23117"},"cell_type":"markdown","source":"Changing how the game is played is difficult for those of us who have watched the game for our entire lives. However, change is necessary to preserve the athletes who play the game currently and their lives after their time is finished in the sport. \n\nThanks to the NFL for bringing safety to the forefront of the sport!"}],"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"}},"nbformat":4,"nbformat_minor":1}