{"cells":[{"metadata":{"trusted":true,"_uuid":"4a04927e2ea41ba1b3fd0df263bd8e3260531e3a"},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom collections import Counter # counting instances\nimport re # parsing play descriptions\nimport matplotlib.pyplot as plt # data visualizations\nfrom scipy.stats import ttest_ind # signficance test\nimport os\nprint(os.listdir(\"../input\"))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f10167f1585320808c4002889517505334336585"},"cell_type":"markdown","source":"# Data Orientation"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":false},"cell_type":"markdown","source":"## 1. How often and what kinds of concussions occur on punt plays? "},{"metadata":{"trusted":true,"_uuid":"f835689adcdc327757bb7c8fdd7c33e6c4f4ef33"},"cell_type":"code","source":"# Punt Play Information\nplay_info_pd = pd.read_csv(\"../input/play_information.csv\")\nplay_info_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0bd586d01d8e0c95aa90750cca4456d55c5c99eb"},"cell_type":"code","source":"play_info_pd.Play_Type.unique() # All the plays are punts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"724e9c5d8328b0f36e0fe7e056c2fa6cab9f9e6c"},"cell_type":"code","source":"# Concussion (ccus) Information\nccus_review_pd = pd.read_csv(\"../input/video_review.csv\")\nccus_review_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a24ac2407bae81da1e1b7b0044bddbab73fed14a"},"cell_type":"code","source":"# Other files to consider\nvideo_replay = pd.read_csv(\"../input/video_footage-injury.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0541c234f3a5952f1de645ce224374c530cc58b0"},"cell_type":"code","source":"# Count varying activities\nplayer_activity_dict = Counter(ccus_review_pd.Player_Activity_Derived)\npartner_activity_dict = Counter(ccus_review_pd.Primary_Partner_Activity_Derived)\nff_dict = Counter(ccus_review_pd.Friendly_Fire)\nimpact_dict = Counter(ccus_review_pd.Primary_Impact_Type)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"246a4320d98107a03802f298b0aad86502e820ed"},"cell_type":"code","source":"print(\"Concussions occur on\",round(100*ccus_review_pd.shape[0] / play_info_pd.shape[0],2),\"% of punt plays\") \nprint(\"\\nConcussed Players Activity:\")\nfor activity in player_activity_dict.keys():\n    print(activity+':',round(100*player_activity_dict[activity]/ccus_review_pd.shape[0],2), '%')\nprint(\"\\nConcussed Partners Activity:\")\nfor activity in partner_activity_dict.keys():\n    if pd.isnull(activity):\n        continue\n    print(activity+':',round(100*partner_activity_dict[activity]/ccus_review_pd.shape[0],2), '%')\nprint('\\nFriendly Fire Concussions occur on', round(100*ff_dict['Yes']/ccus_review_pd.shape[0],2), '% of concussions')\nprint('\\nImpact Area:')\nfor area in impact_dict.keys():\n    print(area+':',round(100*impact_dict[area]/ccus_review_pd.shape[0],2), '%')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9692153466121a6d11f7ef0aeb9e1e13cae27b5e"},"cell_type":"markdown","source":"## 2. Which positions get concussions during punts?"},{"metadata":{"trusted":true,"_uuid":"8afd155f44a62471e6ccaffcc9e20bfbc274d10b"},"cell_type":"code","source":"player_pos_pd = pd.read_csv('../input/player_punt_data.csv').drop(['Number'], axis=1)\nplayer_pos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"565a58050366e957ef749f18b57abb349d65d7ab"},"cell_type":"code","source":"punt_pos_pd = pd.read_csv('../input/play_player_role_data.csv')\npunt_pos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5416458bc08957be82105eed30bbdd68454c6f4c"},"cell_type":"code","source":"video_replay = pd.read_csv(\"../input/video_footage-injury.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bd5e68e849af6913824bee23550a8ac835080786"},"cell_type":"code","source":"ccus_positions_pd = ccus_review_pd.join(player_pos_pd.set_index('GSISID'), on='GSISID', how='left').drop_duplicates()\nccus_positions_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3eb7d64ae53fff72a5a61796cbfdba3a10c351d5"},"cell_type":"code","source":"ccus_both_positions_pd = pd.merge(ccus_positions_pd, punt_pos_pd,  how='left', on=['GSISID','GameKey','PlayID','Season_Year'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a544443a3442d68882451619cc74ee26504c181b"},"cell_type":"code","source":"ccus_both_positions_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fafd4a6c5ffa8751050baa6e11096db4c6b2b0ba"},"cell_type":"code","source":"# Count concussions per position\nreal_pos_dict = Counter(ccus_both_positions_pd.Position)\npunt_pos_dict = Counter(ccus_both_positions_pd.Role)\ncoverage_pos = ['GL','PLW','PLT','PLG','PLS','PRG','PRT','PRW','PC','PPR','P','GR']\nreturn_pos = ['VR','PDR1','PDR2','PDR3','PDL3','PDL2','PDL1','VL','PLR','PLM','PLL','PFB','PR']\ncoverage_ccus = ccus_both_positions_pd[ccus_both_positions_pd.Role.isin(coverage_pos)].shape[0]\nreturn_ccus = ccus_both_positions_pd[ccus_both_positions_pd.Role.isin(return_pos)].shape[0]\nprint(\"Concussed Players Off/Def Position:\")\nfor pos in real_pos_dict.keys():\n    print(pos+':',round(100*real_pos_dict[pos]/ccus_review_pd.shape[0],2), '%')\nprint(\"\\nConcussed Players Punt Position:\")\nfor pos in punt_pos_dict.keys():\n    print(pos+':',round(100*punt_pos_dict[pos]/ccus_review_pd.shape[0],2), '%')\nprint(round(100*coverage_ccus/ccus_review_pd.shape[0],2),'% concussions on coverage,',round(100*return_ccus/ccus_review_pd.shape[0],2),'% concussions on return')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"57e2f1e981f4d6c9af731af71d57e4f2e7163279"},"cell_type":"markdown","source":"## 3. What action led to these concussions? [subjective video review]"},{"metadata":{"trusted":true,"_uuid":"cab424180c1434224c7edf9eee65ddf1d5d9ce30"},"cell_type":"code","source":"video_replay_pd = pd.read_csv(\"../input/video_footage-injury.csv\")[['gamekey','playid','season','PREVIEW LINK (5000K)']]\nvideo_replay_pd.columns = ['GameKey','PlayID','Season_Year','Video']\nvideo_replay_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7ebb911865adea6266f0b481991067b0b95015ce"},"cell_type":"code","source":"ccus_videos_pd = pd.merge(ccus_both_positions_pd, video_replay_pd,  how='left', on=['GameKey','PlayID','Season_Year'])\nccus_videos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f1dceee1ed41a2b56c53a69d0a4f58288976decd"},"cell_type":"code","source":"#build dic bc I'm lazy\n# count = 0\n# for role in ccus_videos_pd.Role:\n#     print(\"'\"+role+\"':\",count,\",\")\n#     count += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6e9bd3bb6c8b6504307f0b1190d92ccf16c2b4be"},"cell_type":"code","source":"action_dict = {\n'PLW': 'Tackling PR, foot/ground to head' ,\n'GL': 'Blindside block right',\n'GR': 'Diving for fumble on muff' ,\n'PRT': 'Group Tackling PR' ,\n'PRT': 'Blindside block right' ,\n'PRW': 'H2H Block on line' ,\n'VR': 'head down block' ,\n'PFB': 'Pair of blockers run into' ,\n'PR': 'tackling during return' ,\n'PLG': 'blocked, head to ground near line',\n'PLG': 'pair of blockers run into during pursuit' ,\n'PRG': 'tackling PR' ,\n'PR': 'big hit during return' ,\n'P': 'tackled' ,\n'PLW': 'chop block knee to head' ,\n'GL': 'blocked into PR' ,\n'PLG': 'missed tackle' ,\n'GL': 'pair of blockers run into',\n'GL': 'head to body tackle' ,\n'PRG': 'blocked at the line' ,\n'PLT': 'blocked chasing PR' ,\n'PLG': 'blocked at the line' ,\n'PPR': 'group tackle' ,\n'PLS': 'blindside block' ,\n'PLT': 'H2H tackle' ,\n'PR': 'PR tackle' ,\n'PLW': 'tackle to ground on line' ,\n'PDR1': 'blocking for PR' ,\n'PRG': 'missed tackle, FF knee to head' ,\n'PR': 'big hit on return' ,\n'PDL2': 'H2H throwing big block' ,\n'PLL': 'H2H throwing big block' ,\n'PR': 'hit on return' ,\n'PRW': 'blocking at line' ,\n'PLS': 'H2H during tackle' ,\n'PLW': 'H2H during block at line' ,\n'PRG': 'ran into pair of blockers during tackle' ,\n}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"59595aeef181f5746d8899156d16c23c3419b478"},"cell_type":"code","source":"# Need Player number so I can follow them on video replay...\n# ... merging causes duplicate rows so quick fix is to work with two tables\nplayer_pos_pd = pd.read_csv('../input/player_punt_data.csv')\nplayer_pos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1430360c2dee32c2f897d246ed8ff9f85241dfbb"},"cell_type":"code","source":"ccus_videos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1c34e5a7bc433450efe47788fc620e61c6a54de7"},"cell_type":"code","source":"# Manually iterate through each video to check film for actions\n# number = player_pos_pd[player_pos_pd.GSISID == ccus_videos_pd.loc[i].GSISID].Number\n# if number.shape[0] > 1:\n#     number = list(number)[0]\n# else:\n#     number = number.item()\n# print(ccus_videos_pd.loc[i].Video, ccus_videos_pd.loc[i].Role, number)\n\n# i = i + 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"aee18c03588c193c23ad89f8cba1c8b4fca29203"},"cell_type":"markdown","source":"#### While PRs get the most concussions and nearly half of all return concussions of all positions, it is only 13.5% of all concussions. The most common scenario for concussion is a punt coverage looking to make a tackle and getting blocked or "},{"metadata":{"_uuid":"fd534e28ab56280acdbe2185f6bb229e5feb973e"},"cell_type":"markdown","source":"# Hypothesis Testing"},{"metadata":{"_uuid":"db6c0147ffc83055f33f63e5e75a471708a5ca0b"},"cell_type":"markdown","source":"# 1. Plays with no returns ***are safer*** than plays where the PR attempts to gain yards \n### [CONFIRMED]"},{"metadata":{"trusted":true,"_uuid":"f00a45bb1bcbbd8a5ff9eb06d297f4ea2de93111"},"cell_type":"code","source":"play_info_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"30604d4bb1a4e9b0bb2bcd0d692cdbe9cc69142c"},"cell_type":"code","source":"ccus_videos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"25ea8a4db87d3e5cb59350263a12e443386c524a"},"cell_type":"code","source":"no_return_str_list = ['fair catch','Touchback', 'out of bounds', 'BLOCKED', 'No Play', 'downed by', \n                     'Delay of Game', 'pass', 'False Start', 'Aborted', 'Fake punt']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c7c42ae712e25258978995970b6e22c1367c8c4f"},"cell_type":"code","source":"# How often are punts returned/not returned (return count) and build list of not_returned to compare to ccuss play list\nno_return_play_strings = []\nreturn_count = 0\ni = 0\nwhile i < len(play_info_pd.PlayDescription):\n    play_string = play_info_pd.loc[i].PlayDescription\n    return_flag = True\n    for phrase in no_return_str_list:\n        if phrase in play_string:\n            no_return_play_strings.append(play_string)\n            return_flag = False\n            break\n    if return_flag:\n        if ('Delay of Game' not in play_string) or ('pass' not in play_string):\n            return_count = return_count + 1\n    i = i + 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cf23aed5be556da4dfb3107953b8f5e7f7c3b968"},"cell_type":"code","source":"# How many concussions happened on no return plays\nno_return_plays_pd = play_info_pd[play_info_pd.PlayDescription.isin(no_return_play_strings)]\nno_return_ccus_pd = pd.merge(ccus_videos_pd,no_return_plays_pd, on=['Season_Year','GameKey','PlayID'], how='inner')\nno_return_ccus_count = no_return_ccus_pd.shape[0]\nreturn_ccus_count = ccus_videos_pd.shape[0] - no_return_ccus_pd.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8716481bdec3211e7d5f87fce310fe7acf982d4e"},"cell_type":"code","source":"print('Punts are returned', round(100*return_count / play_info_pd.shape[0],2), '% of the time')\nprint('Concussions occur on', round(100*return_ccus_count / return_count,2), '% of the time on return punts,')\nprint('in comparison to',round(100*no_return_ccus_count / no_return_plays_pd.shape[0],2), \"% on no return punts\")\nprint('Players are', round((round(100*return_ccus_count / return_count,2)/round(100*no_return_ccus_count / no_return_plays_pd.shape[0],2)),2), 'times more likely to get concussed during a returned punt rather than a non-returned punt')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c5458e7d63307d20fabb3b57dd55948a4a8f6a23"},"cell_type":"markdown","source":" # 2. The average return is < 10 yards\n ### [CONFIRMED]"},{"metadata":{"trusted":true,"_uuid":"a3c4a451f4e73daca26b420c198e713c3610412e"},"cell_type":"code","source":"# Find Return Yards\nreturn_plays_pd = play_info_pd[~play_info_pd.PlayDescription.isin(no_return_play_strings)]\nreturn_yards_list = []\nfor play_string in return_plays_pd.PlayDescription:\n    try:\n        # These are edge cases to cut out\n        if ('Delay of Game' in play_string) or ('pass' in play_string) or ('False Start' in play_string) or ('Aborted' in play_string):\n            continue\n        # 0 yard returns in natural language\n        elif ('for no gain' in play_string) or ('MUFFS' in play_string):\n            yards = 0\n        else:\n            yards = int(re.findall(r'for (\\-*[0-9]*) yard',play_string)[0])\n        return_yards_list.append(yards)\n    except:\n        print(play_string)\n        continue","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a511c9243125007e4deb3c318ea9d1fa3b677cfb"},"cell_type":"code","source":"fig, ax = plt.subplots(dpi=150)  \nax.hist(return_yards_list,  color = \"#A8122A\", bins=100,)\nplt.title('Punt Return Yards')\nplt.xlabel('Yards after Catch')\nplt.ylabel('# of Punts')\nplt.ylim(top=450)\nplt.xlim([-20,100])\nplt.show()\nprint('Average (Mean) Punt Return Length:',round(np.mean(return_yards_list),2))\nprint('Median Punt Return Length:', np.median(return_yards_list))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e53e4adf570e9a69ab47af173d072cee1d9e58ae"},"cell_type":"markdown","source":" # 3. The average Punt is 40 yards\n ### [INCORRECT: Punts averaged 45 yards]"},{"metadata":{"trusted":true,"_uuid":"175705ff4edd159ec2b6860f580d8e7e33d1e17e"},"cell_type":"code","source":"# Find Punt Length\npunt_yards_list = []\nfor play_string in play_info_pd.PlayDescription:\n    try:\n        # These are edge cases to cut out\n        if ('Delay of Game' in play_string) or ('pass' in play_string) or ('False Start' in play_string) or ('Aborted' in play_string):\n            continue\n        # More edge cases for all punt scenarios\n        if ('BLOCKED' in play_string) or ('formation) PENALTY' in play_string):\n            continue\n        else:\n            yards = int(re.findall(r'punts (\\-*[0-9]*) yard',play_string)[0])\n        punt_yards_list.append(yards)\n    except:\n#         print(play_string)\n        continue #There wasn't a punt on this play because it was a fake (language too board to continue statment)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"01502e566bf8ac3a2da408e24a6fb94abb754c54"},"cell_type":"code","source":"# TODO: Why is there a spike at 53 for punt returns?\nfig, ax = plt.subplots(dpi=150)  \nax.hist(punt_yards_list, color = '#ffe599', bins=75,)\nplt.title('Punt Yards')\nplt.xlabel('Length of Punt')\nplt.ylabel('# of Punts')\nplt.xlim([0,100])\nplt.show()\nprint('Average (Mean) Punt Length:',round(np.mean(punt_yards_list),2))\nprint('Median Punt Length:', np.median(punt_yards_list))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"71d299d21a8484d71ec87d45463c6c19c7eb1e36"},"cell_type":"markdown","source":"# 4. Longer Punts are correlated with more concussions\n### [INCORRECT]"},{"metadata":{"trusted":true,"_uuid":"4caf49b69740e021b78bfed0d0e0ec77949a18fa"},"cell_type":"code","source":"punt_length_pd = play_info_pd\n\n# Find Punt Length\npunt_yards_list = []\n# Run the same as above but flag all non-returns so that I can cut them post merge\nfor play_string in play_info_pd.PlayDescription:\n    try:\n        # These are edge cases to cut out\n        if ('Delay of Game' in play_string) or ('pass' in play_string) or ('False Start' in play_string) or ('Aborted' in play_string):\n            yards = 300\n        # More edge cases for all punt scenarios\n        if ('BLOCKED' in play_string) or ('formation) PENALTY' in play_string):\n            yards = 300\n        else:\n            yards = int(re.findall(r'punts (\\-*[0-9]*) yard',play_string)[0])\n        punt_yards_list.append(yards)\n    except:\n        # There wasn't a punt on this play because it was a fake (language too board to continue statment)\n        punt_yards_list.append(300)\n    \n    \npunt_length_pd['punt_length'] = punt_yards_list\npunt_length_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0a4a3d0c16fa5843de57b2ac8a4c1b735bf2082c"},"cell_type":"code","source":"ccuss_length_pd = pd.merge(ccus_videos_pd, punt_length_pd, on=['Season_Year','GameKey','PlayID'], how='inner')\nccuss_length_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"df6542b4ad144cf59e2d7c08c2d77e436673a66c"},"cell_type":"code","source":"fortyfive_plus_ccuss_count = ccuss_length_pd[ccuss_length_pd.punt_length <= 45].shape[0]\nfortyfive_minus_ccuss_count = ccuss_length_pd[ccuss_length_pd.punt_length != 300].shape[0] - fortyfive_plus_ccuss_count\nfortyfive_plus_count = punt_length_pd[punt_length_pd.punt_length <= 45].shape[0]\nfortyfive_minus_count = punt_length_pd[punt_length_pd.punt_length != 300].shape[0] - fortyfive_plus_count","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"111aae2a9b8eaf971900a10cb9e08086f5e569ee"},"cell_type":"code","source":"print('Concussions occur on', round(100*fortyfive_plus_ccuss_count / fortyfive_plus_count,2), '% of the time on punts longer than 45yrds,')\nprint('in comparison to',round(100*fortyfive_minus_ccuss_count / fortyfive_minus_count,2), \"% on punts shorter than 45\")\nprint('Players are', round((round(100*fortyfive_minus_ccuss_count / fortyfive_minus_count,2)/round(100*fortyfive_plus_ccuss_count / fortyfive_plus_count,2)),2), 'times more likely to get concussed during a punt longer than 45yrds')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"da690faeace7b7f9506e276350cf87b43d14fab6"},"cell_type":"code","source":"# Check for significance\nccuss_length_mark_pd = ccuss_length_pd[['Season_Year','GameKey','Week','PlayID','punt_length']]\nccuss_length_mark_pd['marker'] = 1\nccuss_length_mark_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"930b046e28735e866f150e30c5abb2a6152530a8"},"cell_type":"code","source":"joined = pd.merge(punt_length_pd, ccuss_length_mark_pd, on=['Season_Year','GameKey','Week','PlayID','punt_length'], how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ac043b94077f712db01002faa3f1b97cca5d6188"},"cell_type":"code","source":"no_ccuss_punts = joined[pd.isnull(joined['marker'])][punt_length_pd.columns]\nccuss_punt_length = ccuss_length_mark_pd.punt_length\nno_ccuss_punt_length = no_ccuss_punts.punt_length","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6efaa1d7963f0ee6e45ddf8b917def35ce34ecfd"},"cell_type":"code","source":"stat, pvalue = ttest_ind(ccuss_punt_length,no_ccuss_punt_length)\nprint('The Line of Scrimmage for concussions, averaging around',round(np.mean(ccuss_punt_length),4), ',\\nis statistically distinct from the line for non-concussions, averaging around',round(np.mean(no_ccuss_punt_length),2),':', pvalue < 0.05)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f63751bd69300c77ee5f81a343b61d4cc309fb60"},"cell_type":"markdown","source":"# 5. Concussions are more likely to occur on punts that are kicked within your own 40yr\n### [CONFIRMED]"},{"metadata":{"trusted":true,"_uuid":"2c2395603d79ce12f21489d65d487cebf1a03240"},"cell_type":"code","source":"play_info_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"28ecf1da7c076210a7ebf8f5c57179ca18c728aa"},"cell_type":"code","source":"ccus_videos_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a9c81460f411e07d1094aca4c141b1714d1a4ffa"},"cell_type":"code","source":"punt_location = []\nfor i in range(play_info_pd.shape[0]):\n    line_of_scrim = play_info_pd.loc[i].YardLine\n    \n    clean_line = re.findall(r'(\\w+) ([0-9]+)',line_of_scrim)[0]\n    \n    team = clean_line[0]\n    line = int(clean_line[1])\n    \n    if team != play_info_pd.loc[i].Poss_Team:\n        line = 100 - line\n    punt_location.append(line)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"84b7af43a4e37e62448e86d307f932d41fdefdbc"},"cell_type":"code","source":"plt.hist(punt_location, bins=60,)\nplt.title('Punt Locations')\nplt.xlabel('Line of Scrimmage')\nplt.ylabel('# of Punts')\nplt.show()\nprint('Average (Mean) Location:',round(np.mean(punt_location),2))\nprint('Median Punt Location:', np.median(punt_location))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"39db895573336812073091d92530229df377c752"},"cell_type":"code","source":"punt_loc_pd = play_info_pd\npunt_loc_pd = punt_loc_pd[['Season_Year','GameKey','Week','PlayID']]\npunt_loc_pd['yard_line'] = pd.Series(punt_location)\npunt_loc_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f9641f9b2aeaf0045bb2606a4716ce3d7a001741"},"cell_type":"code","source":"ccuss_line_pd = pd.merge(ccus_videos_pd, punt_loc_pd, on=['Season_Year','GameKey','PlayID'], how='inner')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"341003b75c7abd406d962be27f6746eabd4c0801"},"cell_type":"code","source":"ccuss_line = list(ccuss_line_pd.yard_line)\nplt.hist(ccuss_line)\nplt.title('Concussed Punt Locations')\nplt.xlabel('Line of Scrimmage')\nplt.ylabel('# of Punts')\nplt.show()\nprint('Average (Mean) Concussed Punt Location:',round(np.mean(ccuss_line),2))\nprint('Median Concussed Punt Location:', np.median(ccuss_line))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"601f0aa26be5856f1bc90b0171f27cc58c17ccea"},"cell_type":"code","source":"# Run T-Test to see if this is significant\nccuss_line_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2c7db60f907066a80d1103408841cceedcd1b17b"},"cell_type":"code","source":"within_forty_ccuss_count = ccuss_line_pd[ccuss_line_pd.yard_line <= 40].shape[0]\noutside_fourty_ccuss_count = ccuss_line_pd.shape[0] - within_forty_ccuss_count\nwithin_fourty_count = punt_loc_pd[punt_loc_pd.yard_line <= 40].shape[0]\noutside_fourty_count = punt_loc_pd.shape[0] - within_fourty_count","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7d02e98be0dae7bfb27c237e4bf759e9c781d4aa"},"cell_type":"code","source":"print('Concussions occur on', round(100*within_forty_ccuss_count / within_fourty_count,2), '% of the time on punts within own 40,')\nprint('in comparison to',round(100*outside_fourty_ccuss_count / outside_fourty_count,2), \"% on punts outside your 40\")\nprint('Players are', round((round(100*within_forty_ccuss_count / within_fourty_count,2)/round(100*outside_fourty_ccuss_count / outside_fourty_count,2)),2), 'times more likely to get concussed during a punt within your own 40')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1ca35f3283e824ce96e30583e1e7481a101eea11"},"cell_type":"code","source":"within_forty_ccuss_count = ccuss_line_pd[ccuss_line_pd.yard_line <= 35].shape[0]\noutside_fourty_ccuss_count = ccuss_line_pd.shape[0] - within_forty_ccuss_count\nwithin_fourty_count = punt_loc_pd[punt_loc_pd.yard_line <= 35].shape[0]\noutside_fourty_count = punt_loc_pd.shape[0] - within_fourty_count\n\nprint('Concussions occur on', round(100*within_forty_ccuss_count / within_fourty_count,2), '% of the time on punts within own 35,')\nprint('in comparison to',round(100*outside_fourty_ccuss_count / outside_fourty_count,2), \"% on punts outside your 35\")\nprint('Players are', round((round(100*within_forty_ccuss_count / within_fourty_count,2)/round(100*outside_fourty_ccuss_count / outside_fourty_count,2)),2), 'times more likely to get concussed during a punt within your own 35')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6a2b4c70610ca7a8ce7ebfdc37f897b8889c78f4"},"cell_type":"code","source":"# Run t test to prove significance \n\nccuss_line_mark_pd = ccuss_line_pd[['Season_Year','GameKey','Week','PlayID','yard_line']]\nccuss_line_mark_pd['marker'] = 1\nccuss_line_mark_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0bab065fb7b84671552bab36f2d3f879cf8a1732"},"cell_type":"code","source":"punt_loc_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2f441092999d0cfbb746bf2d150b8c563effa3f4"},"cell_type":"code","source":"joined = pd.merge(punt_loc_pd, ccuss_line_mark_pd, on=['Season_Year','GameKey','Week','PlayID','yard_line'], how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c69c09070723d4668800ebf22e3401a72759e41d"},"cell_type":"code","source":"no_ccuss_punts = joined[pd.isnull(joined['marker'])][punt_loc_pd.columns]\nccuss_punt_yards = ccuss_line_mark_pd.yard_line\nno_ccuss_punt_yards = no_ccuss_punts.yard_line","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d17848be7b0a80cac02968f3a43f8835a7a70c23"},"cell_type":"code","source":"stat, pvalue = ttest_ind(ccuss_punt_yards,no_ccuss_punt_yards)\nprint('The Line of Scrimmage for concussions, averaging around',round(np.mean(ccuss_punt_yards),4), ',\\nis statistically distinct from the line for non-concussions, averaging around',round(np.mean(no_ccuss_punt_yards),2),':', pvalue < 0.05)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3e4d7d9efc7d65a6f640d60baa5669140cedc02c"},"cell_type":"markdown","source":"# Punt Touchback Impact\n## How effective will this rule be in reducing concussions?"},{"metadata":{"trusted":true,"_uuid":"d5e22819794b5cbad03ea9487b4cb721b7ba2871"},"cell_type":"code","source":"# http://www.espn.com/nfl/statistics/team/_/stat/returning/position/defense\n# Average Kickoff Return Length: 22.98yrds\n# Kickoff Touchback Length: 25yrds\n# Kickoffs into endzone:\n# Kickoffs taken out of endzone: 163\n# https://profootballtalk.nbcsports.com/2017/10/17/kickoff-returners-keep-taking-the-ball-out-of-the-end-zone-costing-their-teams-yards/; football outsiders\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7040c6eae7f5635ae0257998a6306b9bad1ddfc6"},"cell_type":"code","source":"# 2017 Season Kickoff Stats\n# Kickoffs are a good yardstick because they have a touchback (25yrds) that is more than the average kickoff return (21.5yrds) \n# (https://www.teamrankings.com/nfl/stat/touchbacks-per-game?date=2018-02-05) and in 2017 kickoffs have a higher concussion rate (0.6%)\n# the average plays (0.4%)... as do punts (0.5%) (https://www.youtube.com/watch?time_continue=449&v=t_SsIKgwvz4)\n\n# By Oct 17, 2017 there were 163 return taken out of the endzone (profootballtalk)\n# By that date 75 games had been played (wiki)\n# There were an average of 4.96 kickoffs per team per game (https://www.teamrankings.com/nfl/stat/kickoffs-per-game?date=2018-02-05)\n# and touchbacks account for 2.8 of those kickoffs (https://www.teamrankings.com/nfl/stat/touchbacks-per-game?date=2018-02-05)\n# So with 5.6 touchbacks/game, there are currently 420 touchbacks\n# Let's build in the assumption that 25% of those touchbacks are unreturnable-- they go out the back of the endzone (420*.75 = 315)\n# % of players opting to touchback when the option is available = 1 - (163/(163+315)) = 66% \n# Based on data more than half of all punt returns would benefit from a 10yrd touchback, so lets assume 50% have the real option of touchback\n# If 50% of returns have the option and 66% exercise this option, the number of returns would reduce by 33%\n# With returns occuring 33% less, returns reduce from 44% to 29.5%, with no returns occuring on 70.5%\n# Assuming no change in % of concussions occuring the types of punt plays, this will reduce\n\nprint('~New Rule Concussion %:',round(100*((.44*.0105)+(.56*.0016)),2))\nprint('New Rule Concussion %:',round(100*((.295*.0105)+(.705*.0016)),2))\ndelta = round(-100*((((.295*.0105)+(.705*.0016)) - ((.44*.0105)+(.56*.0016))) /((.44*.0105)+(.56*.0016))),2)\nprint('Rule project to result in ',delta,'% reduction in concussion on punt plays')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8fe2e91e6c947e1902a85d658aaa94b24742bd38"},"cell_type":"markdown","source":"# Counter: Will reducing returns actually reduce punt concussions? What if concussions happen on return plays, but not related to the return itself?\n### Test: What % of concussions occur after and directly related to a return attempt?"},{"metadata":{"trusted":true,"_uuid":"9fc5b256308a6322a7369bb95bbfe04e8ff45a12"},"cell_type":"code","source":"i = 0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eb94ef4f247d863d232d538e23ed3ea793babcc9"},"cell_type":"code","source":"# Manually iterate through each video to check film for actions\n# number = player_pos_pd[player_pos_pd.GSISID == ccus_videos_pd.loc[i].GSISID].Number\n# if number.shape[0] > 1:\n#     number = list(number)[0]\n# else:\n#     number = number.item()\n# print(action_list[i])\n# print(ccus_videos_pd.loc[i].Video, ccus_videos_pd.loc[i].Role, number)\n\n# i = i + 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6c82d4175da38ebbfc7b61f2bf5ea5c7c67e3911"},"cell_type":"code","source":"return_involved = 29\nreturn_irrelevant = 8","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4db5ec0574f8cd22632585fd79c68d3c43dfa9dc"},"cell_type":"code","source":"print('Concussions directly related to a return occuring:',round(29/(29+8),2),'%')\nprint('Return Concussions directly related to a return occuring:', round(29/(29+8-no_return_ccus_count),2),'%')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7ff3f6d8686486f30dcf87d108acf48bcd041d35"},"cell_type":"markdown","source":"# Counter: With the increase of fair-catches, there will be an increase in muffed returns, will this increase concussions?"},{"metadata":{"trusted":true,"_uuid":"2a4e0fd7cb74b7e8f055855116cd03bc7170f4aa"},"cell_type":"code","source":"return_plays_pd = play_info_pd[~play_info_pd.PlayDescription.isin(no_return_play_strings)]\nmuff_count = 0\nfor play_string in return_plays_pd.PlayDescription:\n    if 'MUFF' in play_string:\n        muff_count = muff_count + 1\nprint(muff_count,' total muffed punts (',round(100*muff_count/return_plays_pd.shape[0],2),'%)')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cec8e69d537cbd906f38f0fc1ee0d7a06fe22df0"},"cell_type":"code","source":"muff_ccuss_pd = ccus_review_pd\nmuff_ccuss_pd['marker'] = 1\nmuff_joined = pd.merge(return_plays_pd, muff_ccuss_pd, on=['Season_Year','GameKey','PlayID'], how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ee54dbbd6851a557bc3ebcd6ac2ea769c85cdca3"},"cell_type":"code","source":"muff_ccuss_count = 0\nfor i in range(muff_joined.shape[0]):\n    play_string = muff_joined.loc[i].PlayDescription\n    if ('MUFF' in play_string) and (muff_joined.loc[i].marker == 1):\n        muff_ccuss_count = muff_ccuss_count + 1\nprint(muff_ccuss_count,'concussions occured on muffs,')\nprint(round(100*muff_ccuss_count/muff_count,2),'% chance of concussion on a muffed punt')\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8beb2ed50e0ab907e81531295f40fc45ca602f34"},"cell_type":"code","source":"# How often to concussions happen on fumbles?\nfum_ccuss_pd = ccus_review_pd\nfum_ccuss_pd['marker'] = 1\nfumble_joined = pd.merge(play_info_pd, fum_ccuss_pd, on=['Season_Year','GameKey','PlayID'], how='left')\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"459dc6162aafbb98167fd98cfebdea3e6e4203d4"},"cell_type":"code","source":"fumble_count = 0\nfumble_ccuss_count = 0\nfor i in fumble_joined.index:\n    play_string = fumble_joined.loc[i].PlayDescription\n    if ('FUMBLE' in play_string):\n        fumble_count = fumble_count + 1\n        if fumble_joined.loc[i].marker == 1:\n            fumble_ccuss_count = fumble_ccuss_count + 1\nprint(round(100*fumble_count/fumble_joined.shape[0],2),'% chance of a fumble')\nprint(fumble_ccuss_count,'concussions occured on fumbles,')\nprint(round(100*fumble_ccuss_count/fumble_count,2),'% chance of concussion on a fumble punt')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9a0ee42efb02b04a32a8aabc118374b2c1338319"},"cell_type":"markdown","source":"# Counter: How watchable are punts after this rule change?"},{"metadata":{"trusted":true,"_uuid":"b0654163e075c838cb82f8fa85f36ed3ac6cfb66"},"cell_type":"code","source":"# How often is a kick returned for a touchdown?\ntd_count = 0\nfor play_string in return_plays_pd.PlayDescription:\n    if 'TOUCHDOWN' in play_string:\n        if 'FUMBLE' in play_string: # Check which team scored on fumble\n            print(play_string)\n            # Both fumbled TDs were for the defense, so don't count\n        else:   \n            td_count = td_count + 1\nprint(\"\\n\",round(100*td_count/return_plays_pd.shape[0],2),'% chance of returned TD on returned punt')\nprint(round(100*td_count/play_info_pd.shape[0],2),'% chance of returned TD on all punt')\n\nnew_td_amt = td_count/return_plays_pd.shape[0]*(0.66)\nprint(\"\\n\",round(100*new_td_amt,2),'% chance of returned TD on returned punt post rule change')\nprint(round(100*(td_count*(0.66))/play_info_pd.shape[0],2),'% chance of returned TD on all punt post rule change')\n\n# print('Rule reduces chance of TD by', round(((td_count/play_info_pd.shape[0])-(td_count*(0.66))/play_info_pd.shape[0]))/(td_count/play_info_pd.shape[0])),2))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ecfaf3e5821a98032639e4e46eb149a1df717f0b"},"cell_type":"code","source":"# How many penalties are there on returned punts?\npenalty_count = 0\nno_return_pen_count = 0\nfor play_string in return_plays_pd.PlayDescription:\n    if 'PENALTY' in play_string:\n        penalty_count = penalty_count + 1\nfor play_string in no_return_play_strings:\n    if 'PENALTY' in play_string:\n        no_return_pen_count = no_return_pen_count + 1\nprint(round(100*penalty_count/return_plays_pd.shape[0],2),'% chance of penalty on returned punt')\nprint(round(100*no_return_pen_count/len(no_return_play_strings),2),'% chance of penalty on non-returned punt')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c05d28466d69a364d35b973d2dc5979137460c3a"},"cell_type":"markdown","source":"# Will this rule remove the ability for punter to pin teams within their redzone?"},{"metadata":{"trusted":true,"_uuid":"e75783d84c70695150e9586028048ced2f4e205d"},"cell_type":"code","source":"play_info_pd.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d9d89c799a6c7851bea18761131d430d656fd770"},"cell_type":"code","source":"# How many fair catches occur in the redzone?\nfc_count = 0\nfc_red_count = 0\nfor play_string in play_info_pd.PlayDescription:\n    if 'fair catch' in play_string:\n        fc_count = fc_count + 1\n    else:\n        continue\n    yard_line = int(re.findall(r'yards to\\s*[A-Z]*\\s(-*[0-9]*)',play_string)[0])\n    if yard_line <= 20:\n        fc_red_count = fc_red_count + 1\nprint(round(100*fc_red_count/fc_count,2),'% of fair catches occur in redzone')\n\n# How often are kicks within the redzone returned? Beyond that, what areas of the field have highest/lowest return rates?\n\n# Below is the field dict. This will breakdown where punts land on the field, and how often they are fair caught\n# field_fc_dict[key] is the yardline\n# field_fc_dict[key][0] is the number of fair caught balls\n# field_fc_dict[key][1] is the number of punts in that section of field\nfield_fc_dict = {\n    5:[0,0],\n    10:[0,0],\n    15:[0,0],\n    20:[0,0],\n    25:[0,0],\n    30:[0,0],\n    35:[0,0],\n    40:[0,0],\n    45:[0,0],\n    50:[0,0]\n}\n\nfor play_string in play_info_pd.PlayDescription:\n    if ('punt' not in play_string) or ('Touchback' in play_string) or ('BLOCKED' in play_string):\n        continue\n    try:\n        yard_line = int(re.findall(r'yards to\\s*[A-Z]*\\s(-*[0-9]*)',play_string)[0])\n    except:\n        if 'punt' in play_string:\n#             print(play_string)\n            continue\n    for field_section in field_fc_dict.keys():\n        if (yard_line <= int(field_section)) and (yard_line > int(field_section)-5):\n            if 'fair catch' in play_string:\n                field_fc_dict[field_section][0] = field_fc_dict[field_section][0] + 1\n            field_fc_dict[field_section][1] = field_fc_dict[field_section][1] + 1\n            break\n\nprint('\\nTotal Punts and Fair Catch Percentage every 5 yards:')\nfor fs in field_fc_dict.keys():\n    perc = round(100*field_fc_dict[fs][0]/field_fc_dict[fs][1],2)\n    print(fs,'yards:',field_fc_dict[fs][1],'total punts,',field_fc_dict[fs][0],'fair catches (',perc,'%)' )\n        ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bd83728ece1f096f798ff3ca2f1d3b1eae38abe1"},"cell_type":"code","source":"# Graph\nx = list(field_fc_dict.keys())\npunts = [field_fc_dict[fs][1] for fs in x]\nfcs = [field_fc_dict[fs][0] for fs in x]\nfig, ax = plt.subplots(dpi=150)    \nax.bar(x,punts, width = -5, label='punts', color='#ffe599',align='edge')\nax.bar(x,fcs, width = -5, label='fair catches', color='#a8122a',align='edge')\nplt.xlabel('Yard Line')\nplt.ylabel('# of Punts')\nplt.xlim([0,50])\nfor i in range(len(x)):\n    perc = str(round(100*fcs[i]/punts[i],2)) + '%'\n    ax.text(x[i]-5,fcs[i]+12,perc,color='black',fontweight='bold', size = 8)\nplt.title('The number of punts and the number of fair catches \\nthat occur across the field; bucketed every 5 yards',fontsize=10)\nplt.suptitle('Punt Outcome per Yard Line', y=1.05, fontsize=18)\nax.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"db532e496a00f11ff232f0987e485b8fa999d9bc"},"cell_type":"code","source":"# What percent of punts are within the 15? This percent will represent a reduction in solution efficacy\ntot_punts = sum([punts - fcs for punts, fcs in zip(punts, fcs)])\nred_punts = sum([punts - fcs for punts, fcs in zip(punts[:3], fcs[:3])])\nprint(round(100*red_punts/tot_punts,2),'% of returned punts occur within the 15 yard line')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"db8aa5f7dbf7f22f4e47cab32b28a5b2d06dbb64"},"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}