{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"markdown","source":"- This analysis is for getting an idea of what's happening in the punts that result in a concussion. We'll look primarily at who is concussed and the primary partner of the conussed player."},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as mpatches\nfrom IPython.display import Image, display","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"851c8fcdf0e2929c44c01bb77295b15c19b2eb40"},"cell_type":"markdown","source":"## VIDEO SECTION\n#### VIDEO REVIEW\n- <b>Player Punt Data</b>: Player level data that specifies the traditional football position for each player. Each player is identified using his GSISID.\n- <b>Play Player Role Data</b>: Play and player level data that specifies a punt specific player role. This dataset will specify each player that played in each play. A player’s role in a play is uniquely defined by the Gamekey PlayID and GSISID.\n- <b>Video Review</b>: Injury level data that provides a detailed description of the concussion-producing event. Video Review data are only available in cases in which the injury play can be identified. Each video review case can be identified using a combination of GameKey, PlayID, and GSISID. A brief narrative of the play events is provided.\n- <b>Primary Impact Type</b>: gives source of trauma; Unclear means exactly what you think\n- <b>Primary_Partner_GSISID</b>: usual suspects?\n    - If both the player and partner are concuseed, then each player will be listed as a player\n- <b>37 Concussions</b> Identified out of 6681 punts = 0.5538%"},{"metadata":{"trusted":true,"_uuid":"e201d2bf5e9c557cc48fced5fe3827fc26b11037"},"cell_type":"code","source":"player_df = pd.read_csv('../input/NFL-Punt-Analytics-Competition/player_punt_data.csv')\nplay_player_role_df = pd.read_csv('../input/NFL-Punt-Analytics-Competition/play_player_role_data.csv')\nvideo_review_df = pd.read_csv('../input/NFL-Punt-Analytics-Competition/video_review.csv')\nprint(video_review_df.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"17e98f52a3a9b54734a36707a4bb5f325ab581d4"},"cell_type":"code","source":"# Combine Relevant Player Information, Position, Role, Number\nmaster_player_df = pd.merge(player_df, play_player_role_df,\n                          how='inner',\n                          on=['GSISID']).drop(columns=['Season_Year'])\nmaster_player_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e2880d8379b117ba23dc4ed6182fce749353ade0"},"cell_type":"code","source":"# Check summary counts to see if any are even needed\nprint(video_review_df['Player_Activity_Derived'].value_counts())\nprint('---')\nprint(video_review_df['Turnover_Related'].value_counts())\nprint('---')\nprint(video_review_df['Primary_Impact_Type'].value_counts())\nprint('---')\nprint(video_review_df['Primary_Partner_Activity_Derived'].value_counts())\nprint('---')\nprint(video_review_df['Friendly_Fire'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cdd5430076586833e379ea7e251f1f9cb92c6be1"},"cell_type":"markdown","source":"- Observations:\n    - So we know things involve tackling and blocking (you need contact of some sort to have a concussion)\n    - We see no plays were turnover related although play (GameKey: 274, PlayID: 3609) was turnover related by my idea of a turnover. Maybe they're classifying based off wether there was an actual turnover or if there was a fumble/muff/interception going on.\n    - We can see majority of concussions are related to a helmet hitting some other mass minus the one 'unclear' instance\n    - Majority of concussions are not a result of friendly fire\n    - There are 4 plays that have no designated primary_partner: two were helmet-to-ground, 1 was unclear, and 1 was helmet to helmet (H2H).\n        - If you review those videos two latter videos, the 'unclear' designation was a clear helmet to the back of the head of #44 by Houston Player #55/56 (not sure of number; could probably verify with GSISID from NGS data for the play) and for the H2H you can see Dolphins #34 make a diving head tackle on Baltimore #21.\n            - This information you can deduce by looking at the play video later in the analysis. <b>I MIGHT REPLACE THESE NAN AND UNCLEAR LATER WITH THE CORRECT DATA IF IT SEEMS USEFUL FOR MY OWN ANALYSIS</b>"},{"metadata":{"trusted":true,"_uuid":"6b2972d81b756ec18f8f4036279dbcf8aa823430"},"cell_type":"code","source":"# Now that we have a descriptive idea of what's going on, I'm gonna just drop these columns\n# and also clear up the unclear designation and convert it to NaN\ndroppers = ['Player_Activity_Derived', 'Turnover_Related', 'Primary_Partner_Activity_Derived', \n            'Friendly_Fire', 'Season_Year']\nvideo_review_df.drop(columns=droppers, inplace=True)\n\n# Remove 'Unclear' designation\nvideo_review_df.loc[33, 'Primary_Partner_GSISID'] = 'NaN'","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c2f157c80f269a55fc15404921c01cfff1aec03d"},"cell_type":"markdown","source":"## VIDEO FOOTAGE"},{"metadata":{"trusted":true,"_uuid":"76ea7852489b50e215081783a2ad0b2f0b8a6846"},"cell_type":"code","source":"'''Control Video Footage'''\nvideo_footage_control_df = pd.read_csv('../input/NFL-Punt-Analytics-Competition/video_footage-control.csv')\nprint(video_footage_control_df.shape)\nvideo_footage_control_df.tail(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c2919689671ff73b37a25405d94bf004399fb0e8"},"cell_type":"code","source":"# # Use for printing out video links\n# for i in range(len(video_footage_control_df)):\n#     print(video_footage_control_df.loc[i, 'Preview Link'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"46ad284b78474254b904169d4aba8a0c3a6dd064"},"cell_type":"code","source":"'''Concussion Video Footage'''\nvideo_footage_injury_df = pd.read_csv('../input/NFL-Punt-Analytics-Competition/video_footage-injury.csv')\nprint(video_footage_injury_df.shape)\nvideo_footage_injury_df.head(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6a7575e74c33419715b424d94b1eb76b6f369136"},"cell_type":"code","source":"# # Injury Video Links; search for player who is injured; watch the film, be the film....\n# for i in range(len(injured_players)):\n#     print(i, injured_players['PREVIEW LINK (5000K)'][i])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7a215e051a94f09767c741f26b365522877c98e7"},"cell_type":"code","source":"# Preprocess to allow easier join between video review data and the actual footage data\nrename_columns = {'gamekey': 'GameKey', 'playid': 'PlayID', 'season': 'Season_Year'}\nvideo_footage_injury_df.rename(columns=rename_columns, inplace=True)\n\n# Combine Video Review and Video Injury DataFrames to have the injured player and partner player data\ninjury_play = pd.merge(video_review_df, video_footage_injury_df, \n                       how='inner', \n                       on=['GameKey', 'PlayID'])\ninjury_play.head(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f49c92b495119253173c4fd44b422067e1404d65"},"cell_type":"code","source":"# Lets Drop Some More Data I consider uncritical for getting a feel for the data\ndroppers = ['Season_Year', 'Type', 'Week', 'Home_team', 'Visit_Team', 'Qtr']\ninjury_play.drop(columns=droppers, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"54aab906a6b40ca057d7b6d7f87604f6cee16e6f"},"cell_type":"code","source":"# Join Info (their jersey number, position, role) on Players Who are Injured\ninjured_players = pd.merge(injury_play, master_player_df,\n                           how='inner',\n                           on=['GSISID', 'GameKey', 'PlayID'])\n\nprint('Shape:', injured_players.shape)\ninjured_players.head(1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7f3ab89e5461dfc8fded89f790bc3d621a2a443c"},"cell_type":"markdown","source":"- I get the concussed player's information to identify their jersey number in the video. With potentially multiple jersey numbers associated with a player, this was needed information to focus on what events led up to the concussion. I watched the film and cross referenced plays where it was unclear as to the players number with game recaps (googled) to identify the concussed players number."},{"metadata":{"trusted":true,"_uuid":"8a0758c975bfbfa8be1d3f589f090d90ee86cb27"},"cell_type":"code","source":"# Drop Certain Rows After Identifying Concussed Players Jersey Number from video\ndrop_rows = [1, 7, 17, 20, 23, 26, 27, 28, 29, 32, 33, 36, 38, 39, 45, 46, 47, 50, 52, 55, 57]\ninjured_players.drop(labels=drop_rows, inplace=True)\ninjured_players.reset_index(drop=True, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5dd62b840bc7b49e00b49cdb257c4d7af37fddaf"},"cell_type":"markdown","source":"## NGS DATA: CONCUSSION PLAY ANALYSIS\n- <b>Next Gen Stats</b>:player level data that describes the movement of each player during a play. NGS data is processed by BIOCORE to produce relevant speed and direction data. The NGS data is identified using GameKey, PlayID, and GSISID. Player data for each play is provided as a function of time (Time) for the duration of the play.\n- Players are recorded at every <b>10th of a second or 100 milliseconds</b>\n- Field dimensions: 120 yards by 53.3 yards\n- Speed can be calculated with Time and dis\n- <b>Event</b> record pretty regular events"},{"metadata":{"trusted":true,"_uuid":"1c47abf7adf3e86373b41b9d81de4e7b849f3760"},"cell_type":"code","source":"# Read in only concussion data (dataset formed in a different notebook)\n# Contains NGS data for plays involving a concussion\nngs_concussion = pd.read_csv('../input/ngsconcussion/NGS-concussion.csv')\nngs_concussion.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d4ddc7299d2b12ab2604181d0594eba1a2ff9619"},"cell_type":"code","source":"# Convert Primary_Partner_GSISID from str to float\ninjured_players['Primary_Partner_GSISID'] = injured_players['Primary_Partner_GSISID'].astype('float')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bc9a8b2febff1cc2dcdb05440fa1aea6729dad1d"},"cell_type":"markdown","source":"### Reasoning for analyzing speeds\n- Again this notebook is more to explore parts of the play. I wanted to understand what speeds the concussed player and the partner player were running at throughout the play. I care more about distributions than averages. Mostly to see severity of impact. I plot their routes with their corresponding speeds. I do not label each player because it's only used as reference to what's in the actual videos. I do not evaluate 'o' and 'dir' variables because previous analyses didn't seem to give any useful information to me. Maybe it helps if you're a biomechanical engineer."},{"metadata":{"trusted":true,"_uuid":"08db6afc242be0d455a3370b7bf1d4a2815b13db"},"cell_type":"code","source":"from IPython.display import display, HTML\n\ndef make_html(game_key, play_id):\n    return '<img src=\"{}\" style=\"display:inline;margin:1px\"/>'\\\n    .format('../input/ngsconcussion/' + str(game_key) + '_' + str(play_id) + '.gif')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"07859f80d8309279944df6f46172db22d385829e"},"cell_type":"code","source":"# Map Routes of concussed player and partner player\n# and give approximate speeds throughout their route\nfor i in range(len(injured_players)):\n    # Get necessary values for query of NGS data\n    game_key = injured_players.loc[i, 'GameKey']\n    play_id = injured_players.loc[i, 'PlayID']\n    concussed_id = injured_players.loc[i, 'GSISID']\n    partner_id = injured_players.loc[i, 'Primary_Partner_GSISID']\n    print('GameKey:', game_key, 'PlayID:', play_id)\n    print('Play Description:', injured_players.loc[i,'PlayDescription'])\n    print('Primary Impact Type:', injured_players.loc[i, 'Primary_Impact_Type'])\n    print('Concussed:', concussed_id, 'Role:', injured_players.loc[i, 'Role'])\n    print('Partner:', partner_id)\n    # Visualizing play with .gif file\n    display(HTML(''.join(make_html(game_key, play_id))))\n    \n    # Concussed player\n    where_condition = (\n        (ngs_concussion['GameKey'] == game_key)&\\\n        (ngs_concussion['PlayID'] == play_id) &\\\n        (ngs_concussion['GSISID'] == concussed_id))\n    concussion = ngs_concussion[where_condition].copy()\n    # Reorder by Time and reset index\n    concussion.sort_values(by=['Time'], inplace=True)\n    concussion.reset_index(drop=True, inplace=True)\n    \n    # Partner player\n    where_condition = (\n        (ngs_concussion['GameKey'] == game_key)&\\\n        (ngs_concussion['PlayID'] == play_id) &\\\n        (ngs_concussion['GSISID'] == partner_id))\n    partner = ngs_concussion[where_condition].copy()\n    partner.sort_values(by=['Time'], inplace=True)\n    partner.reset_index(drop=True, inplace=True)\n\n    # Variables for Mapping\n    concussion_x = concussion['x']\n    concussion_y = concussion['y']\n    partner_x = partner['x']\n    partner_y = partner['y']\n    speed1 = concussion['dis'] / 0.1\n    speed2 = partner['dis'] / 0.1\n    \n    # Mapping of play\n    sns.set()\n    plt.figure(figsize=(10,5))\n    cmap = plt.get_cmap('coolwarm')\n    plt.scatter(concussion_x, concussion_y, c=speed1, cmap=cmap, alpha=0.5)\n    if partner_id != 'NaN':\n        plt.scatter(partner_x, partner_y, c=speed2, cmap=cmap, alpha=0.5)\n    plt.clim(0, 12)\n    plt.colorbar(label='yards/sec')\n    # Normal length of field is 120 yards\n    plt.xlim(-10, 130)\n    plt.xticks(np.arange(0, 130, step=10),\n               ['End', 'Goal Line', '10', '20', '30', '40', '50', '40', '30', '20', '10', 'Goal Line', 'End'])\n    # Normal width is 53.3 yards\n    plt.ylim(-10, 65)\n    plt.yticks(np.arange(0, 65, 53.3), ['Sideline', 'Sideline'])\n    plt.title('Playing Field')\n    plt.xlabel('yardline')\n    plt.ylabel('width of field')\n    plt.show()\n    print('---')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4f3b9e7b970caefc540530bc824aaf0493dd61f5"},"cell_type":"markdown","source":"- All mentions of a play are in this format: (GameKey, PlayId)\n- Video link for play <b>(281, 1526)</b> is incorrect.\n    - Play can be identified from times (13:52 to 14:03) of video (https://www.youtube.com/watch?v=NsBDbLWcLyM)\n    - Looks like an illegal block above the waist (https://operations.nfl.com/the-rules/nfl-video-rulebook/illegal-block-above-the-waist/) that was not called\n- Note: fastest times for 40 yard dash range from 4.22 - 4.30 seconds, which is equivalent to 9.30 - 9.48 yards/sec\n    - Reference: https://en.wikipedia.org/wiki/40-yard_dash\n- Some players are at moments reaching higher velocities than these amazing 40 yard sprinters average yards/sec. Just guessing there might be shoves in the back with some plays and maybe competition pushes your speeds a bit :P.\n- Some plays result in high impact collisions others are at speeds similar to an average punt play (analysis in a different notebook for a different time). Just hoping this notebook might be useful to someone who likes to see player routes with speed. Cheers!"},{"metadata":{"trusted":true,"_uuid":"bb035414337fde5bd0b703163b02bc40d21401c8"},"cell_type":"markdown","source":"<img src=\"../input/ngsconcussion/149_3663.gif\" width='250px'/>******\n "},{"metadata":{"_uuid":"02f8446495c071ebfd2defcd46a753d7b9f8bd2d"},"cell_type":"markdown","source":"<img src=\"https://i.imgur.com/xgKeain.jpg\" width=\"250px\"/>[](http://)"},{"metadata":{"trusted":true,"_uuid":"094f05ab07079775e6f4de3584cc128e3236d482"},"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"}},"nbformat":4,"nbformat_minor":1}