{"cells":[{"metadata":{"_uuid":"eabd6f1f9864644efb7e0db539bd3ffb2554afbb"},"cell_type":"markdown","source":"# NFL Punt Analytics Competition\n\nLet's begin by analyzing the table with the information about the concussions in the last 2 seasons.\n\n<hr />**Primary table in file: video_review.csv**"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Load video_review.csv data\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport datetime\n\nvideo_review = pd.read_csv(\"../input/video_review.csv\")\nvideo_review.head(3)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cfbb91735b334c1fd73d4982e7172b466676469b"},"cell_type":"markdown","source":"<hr />**Number of concussions by year.**"},{"metadata":{"trusted":true,"_uuid":"87873e82e7eb9c2b275b538017150424bb6183f9","_kg_hide-input":true},"cell_type":"code","source":"# Count injuries by year\ninjuries_by_year = pd.DataFrame(video_review[\"Season_Year\"].value_counts())\ninjuries_by_year.columns = [\"Concussions\"]\ninjuries_by_year.index.name = \"Year\"\n\ntotal_injuries = injuries_by_year.sum()[0]\ninjuries_by_year[\"Share\"] = injuries_by_year[\"Concussions\"] / total_injuries\ninjuries_by_year[\"Share\"] = injuries_by_year[\"Share\"].map(lambda s: round(s * 100, 2))\ninjuries_by_year","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"503629c953e1360a94bfe57fa72002c74f97b0af"},"cell_type":"markdown","source":"The number of injuries remained very similar between the 2016 and 2017 seasons.<hr />\n**Player Activity during concussion event.**"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Count activity derived of injured player\nplayer_activity_derived = pd.DataFrame(video_review[\"Player_Activity_Derived\"].value_counts())\nplayer_activity_derived.columns = [\"Concussions\"]\nplayer_activity_derived.index.name = \"Player Activity\"\n\ntotal_injuries = player_activity_derived.sum()[0]\nplayer_activity_derived[\"Share\"] = player_activity_derived[\"Concussions\"] / total_injuries\nplayer_activity_derived[\"Share\"] = player_activity_derived[\"Share\"].map(lambda s: round(s * 100, 2))\nplayer_activity_derived","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"98b4cdb85cc12ac78c854c7a31632a4717dfc9ba"},"cell_type":"markdown","source":"\"Tackling\" at 35.14% is the most common player activity, followed by \"Blocked at 27.03 %.<hr />\n**Primary Partner Activity during concussion event.**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"3333c13d5136b3e0f7a88a48e70eb9705e692a29"},"cell_type":"code","source":"# Count activity derived of primary player \"causing\" the injury\nprimary_partner_ad = pd.DataFrame(video_review[\"Primary_Partner_Activity_Derived\"].value_counts())\nprimary_partner_ad.columns = [\"Concussions\"]\nprimary_partner_ad.index.name = \"Partner Activity\"\n\ntotal_injuries = primary_partner_ad.sum()[0]\nprimary_partner_ad[\"Share\"] = primary_partner_ad[\"Concussions\"] / total_injuries\nprimary_partner_ad[\"Share\"] = primary_partner_ad[\"Share\"].map(lambda s: round(s * 100, 2))\nprimary_partner_ad","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"65dac18d49de33024a3b74b1ffa930e919ac3a9e"},"cell_type":"markdown","source":"As in the previous table, \"Tackling\" and \"Blocked\" are in the top with 28.57%.<hr />\n**Friendly Fire?**"},{"metadata":{"trusted":true,"_uuid":"3c1ef01b4979c18d6864d0fdd50a9df2865996ec","_kg_hide-input":true},"cell_type":"code","source":"# Count whether impact was with teammate\nfriendly_fire = pd.DataFrame(video_review[\"Friendly_Fire\"].value_counts())\nfriendly_fire.columns = [\"Concussions\"]\nfriendly_fire.index.name = \"Friendly Fire\"\n\ntotal_injuries = friendly_fire.sum()[0]\nfriendly_fire[\"Share\"] = friendly_fire[\"Concussions\"] / total_injuries\nfriendly_fire[\"Share\"] = friendly_fire[\"Share\"].map(lambda s: round(s * 100, 2))\nfriendly_fire","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ba958f577041379b98ff7d07dc2d2da2bdaf4364"},"cell_type":"markdown","source":"80% of concussions occurred with players of the opposing teams. Only 17.14% with teammates.<hr />\n**Primary Type of Impact**"},{"metadata":{"trusted":true,"_uuid":"2331894c51020da4336e34fb8552685bf3cae9a1","_kg_hide-input":true},"cell_type":"code","source":"# Count injuries by the primary type of impact\nprimary_impact_type = pd.DataFrame(video_review[\"Primary_Impact_Type\"].value_counts())\nprimary_impact_type.columns = [\"Concussions\"]\nprimary_impact_type.index.name = \"Impact Type\"\n\ntotal_injuries = primary_impact_type.sum()[0]\nprimary_impact_type[\"Share\"] = primary_impact_type[\"Concussions\"] / total_injuries\nprimary_impact_type[\"Share\"] = primary_impact_type[\"Share\"].map(lambda s: round(s * 100, 2))\nprimary_impact_type","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"576619a5b842ff88d51831fda4b8214282d8c914"},"cell_type":"markdown","source":"\"Helmet-to-body\" and \"Helmet-to-helmet\" account for 91.9% of total concussions.<hr />\n**Joining information from all tables in the dataset**"},{"metadata":{"trusted":true,"_uuid":"a923c574e16c7a90b44e22727caf2261ce386c9c","_kg_hide-input":true},"cell_type":"code","source":"# Load related data files\ngame_data = pd.read_csv(\"../input/game_data.csv\")\nplay_information = pd.read_csv(\"../input/play_information.csv\")\nplayer_punt_data = pd.read_csv(\"../input/player_punt_data.csv\")\nplay_player_role_data = pd.read_csv(\"../input/play_player_role_data.csv\")\nvideo_footage_injury = pd.read_csv(\"../input/video_footage-injury.csv\")\n\n# Prepare tables for merging\nvideo_review[\"Primary_Partner_GSISID\"] = video_review[\"Primary_Partner_GSISID\"].fillna(0).replace(\"Unclear\", 0).astype(\"int64\")\nplayer_punt_data = player_punt_data.groupby(\"GSISID\").agg({\"Number\": lambda x: \",\".join(x), \"Position\": lambda x: \",\".join(x.unique()) })\nvideo_footage_injury = video_footage_injury.rename(columns = {\"season\": \"Season_Year\", \"Type\": \"Season_Type\", \"Home_team\": \"Home_Team\", \"Qtr\": \"Quarter\", \"gamekey\": \"GameKey\", \"playid\": \"PlayID\"})\n\n# Merge tables\nshared_columns = [\"Season_Year\", \"GameKey\"] # between video_review and game_data\nconcussion_data = video_review.merge(game_data, how = \"left\", left_on = shared_columns, right_on = shared_columns)\n\nshared_columns = [\"Season_Year\", \"GameKey\", \"PlayID\", \"Season_Type\", \"Week\"] # between concussion_data and play_information (also \"Game_Date\" but in different formats)\nconcussion_data = concussion_data.merge(play_information, how = \"left\", left_on = shared_columns, right_on = shared_columns, suffixes = (\"\", \"_play_inf\"))\n\nshared_columns = [\"GSISID\"] # between concussion_data and player_punt_data\nconcussion_data = concussion_data.merge(player_punt_data, how = \"left\", left_on = shared_columns, right_on = shared_columns)\nconcussion_data = concussion_data.merge(player_punt_data, how = \"left\", left_on = [\"Primary_Partner_GSISID\"], right_on = shared_columns, suffixes = (\"_Injured\", \"_Partner\"))\n\nshared_columns = [\"Season_Year\", \"GameKey\", \"PlayID\", \"GSISID\"] # between concussion_data and play_player_role_data\nconcussion_data = concussion_data.merge(play_player_role_data, how = \"left\", left_on = shared_columns, right_on = shared_columns)\nconcussion_data = concussion_data.merge(play_player_role_data, how = \"left\", left_on = [\"Season_Year\", \"GameKey\", \"PlayID\", \"Primary_Partner_GSISID\"], right_on = shared_columns, suffixes = (\"_Injured\", \"_Partner\"))\n\nshared_columns = [\"Season_Year\", \"GameKey\", \"PlayID\", \"Season_Type\", \"Week\", \"Home_Team\", \"Visit_Team\", \"Quarter\"] # between concussion_data and video_footage_injury , (also \"PlayDescription\")\nconcussion_data = concussion_data.merge(video_footage_injury, how = \"left\", left_on = shared_columns, right_on = shared_columns, suffixes = (\"\", \"_Other\"))\nconcussion_data.head(3)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"594ed4e94a245bdb5078aa5ed0d0160391ff017d"},"cell_type":"markdown","source":"Before watching the videos, we need to summarize the information that we are going to need while watching.<hr />\n**Summarized Table**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"0dcd7dbfd2c3763d6617fd2a3a824b2d5aa3a456"},"cell_type":"code","source":"# We don´t know the team of the players, so let's add that column\nkicking_team_positions = ['PLS', 'PLG', 'PRG', 'PLT', 'PRT', 'PLW', 'PRW', 'GL', 'GR', 'PPR', 'P'] # from Data, Appendix 1\nreturning_team_positions = ['PDL1', 'PDL2', 'PDL3', 'PDR1', 'PDR2', 'PDR3', 'PLL', 'PLM', 'PLR', 'PLL1', 'VLo', 'VR', 'PFB', 'PR'] # from Data, Appendix 2\n\ndef role_in_kicking_team(role):\n    if role in kicking_team_positions:\n        return \"Kicking\"\n    elif role in returning_team_positions:\n        return \"Returning\"\n\ndef team_of_player(is_kicking, poss_team, home_visit_teams):\n    if is_kicking == \"Kicking\":\n        return poss_team\n    elif is_kicking == \"Returning\":\n        return home_visit_teams.replace(poss_team, \"\").replace(\"-\", \"\")\n    \ndef add_information(row):\n    home_visit = row[\"Home_Team_Visit_Team\"]\n    poss = row[\"Poss_Team\"]\n    is_player_punting = role_in_kicking_team(row[\"Role_Injured\"])\n    is_partner_punting = role_in_kicking_team(row[\"Role_Partner\"])\n\n    row[\"Player_Kicking/Return\"] = is_player_punting\n    row[\"Player_Team\"] = team_of_player(is_player_punting, poss, home_visit)\n    row[\"Partner_Kicking/Return\"] = is_partner_punting\n    row[\"Partner_Team\"] = team_of_player(is_partner_punting, poss, home_visit)\n    \n    return row\n\nconcussion_data = concussion_data.apply(add_information, axis = \"columns\")\n\n# Now let's clean up the columns that we don't need and format the information\n# Game - Type, Year, Week, Teams Home-Visit, GameKey, PlayID\n# Impact_Type\n# Player Injured - Team, Numbers, Role, Activity, Kicking/Return Team\n# Primary Partner - Team, Numbers, Role, Activity, Kicking/Return Team \n# Video Link\ndef get_summary(row):\n    return row[[\"Season_Type\", \"Season_Year\", \"Week\", \"Home_Team_Visit_Team\", \"GameKey\", \"PlayID\",\n                \"Primary_Impact_Type\", \"Player_Team\", \"Number_Injured\", \"Role_Injured\", \"Player_Activity_Derived\", \"Player_Kicking/Return\",\n                \"Partner_Team\", \"Number_Partner\", \"Role_Partner\", \"Primary_Partner_Activity_Derived\", \"Partner_Kicking/Return\",\n                \"PREVIEW LINK (5000K)\"]]\n\nsummarized_concussion_data = concussion_data.apply(get_summary, axis = \"columns\")\nsummarized_concussion_data = summarized_concussion_data.rename(columns = {\"Season_Type\": \"Type\", \"Season_Year\": \"Year\", \"Home_Team_Visit_Team\": \"Game (Home-Visit)\", \"Number_Injured\": \"Player_Numbers\", \"Player_Activity_Derived\": \"Player_Activity\", \"Role_Injured\": \"Player_Role\", \"Primary_Impact_Type\": \"Impact_Type\",  \"Number_Partner\": \"Partner_Numbers\", \"Primary_Partner_Activity_Derived\": \"Partner_Activity\", \"Role_Partner\": \"Partner_Role\", \"PREVIEW LINK (5000K)\": \"Video Link\"})\nsummarized_concussion_data.head(3)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5c8b6cd9e353f50d1de806b6fc72f62543ef8195"},"cell_type":"markdown","source":"Let's take a break to analyze the videos.<hr />\n**Observations from the videos**<br />\nAfter analyzing all the videos, most concussions fall under one or more of the following categories:\n\n* **Poor Tackling**  - A lot of concussions occurred with a player \"Tackling\" with the head first onto the body or helmet of another (e.g. PlayID 1988, GameKey 506, player MIA-34 hit helmet-to-helmet player BLT-21 trying to tackle him).\n* **Accidental** - Some were accidental (e.g. PlayID 2667, GameKey 296, players TEN-36 and TEN-37 collided helmet-to-helmet trying to tackle the punt returner).\n* **Dirty Hit** - Some were unnecessary \"dirty\" hits (e.g. PlayID 2587, GameKey 21, player TEN-28 knock out player CAR-86 helmet-to-helmet very far from the ball).\n* **Poor Blocking** - A few were very close to the line of scrimmage with players \"Blocking\" and \"Blocked\" colliding (e.g. PlayID 978, GameKey 607, player DEN-53 trying to block the punt, hit helmet-to-helmet player IND-85 who was blocking).\n* **Ground**\n* **Unclear**\n\nNOTE: Most concussions occured with the hit delivered to the side of the helmet, even when the hit did not looked to be as hard/fast as the mayority."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"89bb64bdec748921229c8df1250c23f82f75dbf8"},"cell_type":"code","source":"# Let's add the categories to the table\nplays_cat_list = [\"Poor Tackling\", \"Dirty Hit\", \"Poor Tackling\", \"Poor Tackling\", \"Accidental\", \"Poor Blocking\", \n             \"Poor Blocking\", \"Poor Blocking\", \"Poor Tackling\", \"Ground\", \"Dirty Hit\", \"Poor Tackling\", \n             \"Dirty Hit\", \"Poor Tackling\", \"Poor Blocking\", \"Poor Tackling\", \"Unclear\", \"Dirty Hit\", \n             \"Accidental\", \"Poor Tackling\", \"Dirty Hit\", \"Dirty Hit\", \"Accidental\", \"Dirty Hit\", \n             \"Poor Tackling\", \"Poor Tackling\", \"Ground\", \"Poor Blocking\", \"Accidental\", \"Poor Tackling\",\n             \"Poor Blocking\", \"Poor Blocking\", \"Poor Tackling\", \"Dirty Hit\", \"Poor Tackling\", \"Poor Blocking\", \"Accidental\"]\nplays_cat_serie = pd.Series(plays_cat_list, index = list(range(0, 37)))\nconcussion_data[\"Cat_Play\"] = plays_cat_serie\n\n# Count injuries by category\ncat_play = pd.DataFrame(concussion_data[\"Cat_Play\"].value_counts())\ncat_play.columns = [\"Concussions\"]\ncat_play.index.name = \"Category\"\n\ntotal_injuries = cat_play.sum()[0]\ncat_play[\"Share\"] = cat_play[\"Concussions\"] / total_injuries\ncat_play[\"Share\"] = cat_play[\"Share\"].map(lambda s: round(s * 100, 2))\ncat_play","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cb2b2e99d8cdd5c59325eb56b2f767e1f5dd9b8e"},"cell_type":"markdown","source":"<hr />\n**Concussions in Preseason, Regular Season and Playoffs**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"a99f88657100ba65e0b51894fc903422052f672a"},"cell_type":"code","source":"# Count injuries by game type\ngame_type_injuries = pd.DataFrame(summarized_concussion_data[\"Type\"].value_counts())\ngame_type_injuries = game_type_injuries.append(pd.Series({\"Type\": 0}, name = \"Post\"))\n\n# Number of total games by type\ngame_type_totals = game_data[\"Season_Type\"].value_counts()\ngame_type_injuries = game_type_injuries.join(game_type_totals)\n\ngame_type_injuries.index.name = \"Game Type\"\ngame_type_injuries.columns = [\"Concussions\", \"Total Games\"]\n\n# Ratio between number of games and injuries\ngame_type_injuries[\"Ratio\"] = game_type_injuries[\"Concussions\"] / game_type_injuries[\"Total Games\"]\ngame_type_injuries[\"Ratio\"] = game_type_injuries[\"Ratio\"].map(lambda s: round(s, 3))\ngame_type_injuries.sort_values(by = \"Ratio\", ascending = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f49e34c7f560299bfe33bef7e650dbf74d358776"},"cell_type":"markdown","source":""},{"metadata":{"_uuid":"395d10a446c69d20996154328eb11bdae02aa642"},"cell_type":"markdown","source":"Based on the ratio, 1 concussion every 10.87 games occurred in Pre-Season, 1 every 20.40 in Regular Season. Almost double the amount.<hr />\n**Concussions by Kicking Team or ReturningTeam**"},{"metadata":{"trusted":true,"_uuid":"615b5a50d759eb28211c4d69b958792486bbdb6c","_kg_hide-input":true},"cell_type":"code","source":"# Count injuries by kicking/returning punt\nkick_return_team = pd.DataFrame(summarized_concussion_data[\"Player_Kicking/Return\"].value_counts())\nkick_return_team.columns = [\"Concussions\"]\nkick_return_team.index.name = \"Team\"\n\ntotal_injuries = kick_return_team.sum()[0]\nkick_return_team[\"Share\"] = kick_return_team[\"Concussions\"] / total_injuries\nkick_return_team[\"Share\"] = kick_return_team[\"Share\"].map(lambda s: round(s * 100, 2))\nkick_return_team","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"158149820bc0ea6228ba3d22fdbe617a36d8985d"},"cell_type":"markdown","source":"Most concussions happened to the player in the kicking team (73%).<hr />\n**Concussions by day of the game in the regular season**"},{"metadata":{"trusted":true,"_uuid":"aa66698c911c4bce69ec52447a1d505d009cf7e8","_kg_hide-input":true},"cell_type":"code","source":"# Count injuries by day of the game\ngame_day = pd.DataFrame(concussion_data.loc[concussion_data.Season_Type == \"Reg\"][\"Game_Day\"].value_counts())\ngame_day.index.name = \"Game_Day\"\ngame_day.columns = [\"Concussions\"]\n\n# Number of total games by type\ngame_day_totals = game_data.loc[game_data.Season_Type == \"Reg\"][\"Game_Day\"].value_counts()\ngame_day = game_day.join(game_day_totals)\n\ngame_day.index.name = \"Regular Season\"\ngame_day.columns = [\"Concussions\", \"Total Games\"]\n\n# Ratio between number of games and injuries\ngame_day[\"Ratio\"] = game_day[\"Concussions\"] / game_day[\"Total Games\"]\ngame_day[\"Ratio\"] = game_day[\"Ratio\"].map(lambda s: round(s, 3))\ngame_day.sort_values(by = \"Ratio\", ascending = False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1ca6bab055172df7c5b52c01ec9c32b66717406b"},"cell_type":"markdown","source":"2016 season had a large number of saturday games because because xmas day was on sunday and most games were played on saturday.<br />Based on the ratio, 1 concussion every 8.77 games occurred in Thursday, 1 every 23.80 games in Sunday and 1 in every 17.54 games in Monday.<hr />\n**Concussions by the role of the concussed player**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"86268f69b2dde5cc2bafaa44cbad49565dc504c9"},"cell_type":"code","source":"# Count injuries by role of injured player\nrole_injured = pd.DataFrame(concussion_data[\"Role_Injured\"].value_counts())\nrole_injured.columns = [\"Concussions\"]\nrole_injured.index.name = \"Position\"\n\ntotal_injuries = role_injured.sum()[0]\nrole_injured[\"Share\"] = role_injured[\"Concussions\"] / total_injuries\nrole_injured[\"Share\"] = role_injured[\"Share\"].map(lambda s: round(s * 100, 2))\nrole_injured","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d53665c6bd4b1dee4be6333809920955a1dab6d6"},"cell_type":"markdown","source":"Punt returner suffered the most concussions at 13.51%.<hr />\n**Concussions by quarter**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"192705243a1217ff2f75d6d6e9490910933e06b4"},"cell_type":"code","source":"# Count injuries by quarter\nquarter_inj = pd.DataFrame(concussion_data[\"Quarter\"].value_counts())\nquarter_inj.columns = [\"Concussions\"]\nquarter_inj.index.name = \"Quarter\"\n\ntotal_injuries = quarter_inj.sum()[0]\nquarter_inj[\"Share\"] = quarter_inj[\"Concussions\"] / total_injuries\nquarter_inj[\"Share\"] = quarter_inj[\"Share\"].map(lambda s: round(s * 100, 2))\nquarter_inj","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4d5c5af77e1938c0c2776c56ce8f4aa175202ae4"},"cell_type":"markdown","source":"Most occurred in the third quarter (37.84%) followed by second quarter (29.73%)<hr />\n**Let's get a table where we can see whether the team is winning, losing or tied at the time of the concussion**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"a96eaf6bcb5b92c6bfa2908d2be808810369414b"},"cell_type":"code","source":"def get_score_diff(row):\n    teams = row[\"Home_Team_Visit_Team\"].split(\"-\")\n    home_team = teams[0]\n    visit_team = teams[1]\n    \n    scores = row[\"Score_Home_Visiting\"].split(\"-\")\n    home_score = int(scores[0].rstrip())\n    visit_score = int(scores[1].lstrip())\n    \n    if row[\"Player_Team\"] == home_team:\n        score_def = home_score - visit_score\n    elif row[\"Player_Team\"] == visit_team:\n        score_def = visit_score - home_score\n        \n    if score_def == 0:\n        status_score = \"Tied\"\n    elif score_def < 0:\n        status_score = \"Losing\"\n    else:\n        status_score = \"Winning\"\n    \n    row[\"Score_Diff\"] = score_def\n    row[\"Status_Score\"] = status_score\n    \n    return row\n\nscore_diff = concussion_data[[\"Home_Team_Visit_Team\", \"Score_Home_Visiting\", \"Player_Team\"]]\nscore_diff = score_diff.apply(get_score_diff, axis = \"columns\")\nscore_diff.head(3)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"2d0942dab30f5924b61b770fb29066f69c337e6a"},"cell_type":"code","source":"# Count injuries by game status\ngame_status = pd.DataFrame(score_diff[\"Status_Score\"].value_counts())\ngame_status.columns = [\"Concussions\"]\ngame_status.index.name = \"Game Status\"\n\ntotal_injuries = game_status.sum()[0]\ngame_status[\"Share\"] = game_status[\"Concussions\"] / total_injuries\ngame_status[\"Share\"] = game_status[\"Share\"].map(lambda s: round(s * 100, 2))\ngame_status","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fd9911df3b8647b5a28205947c52a11972458417"},"cell_type":"markdown","source":"* More than half occurred to a player of the team losing the game at the time of concussion.<hr />\n# Next Gen Stats\n**Let's get all the data from the specific plays when a player was concussed.**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"9ce1799cc9fdfb509e6e3e1bdf6e9605e9ea05ac"},"cell_type":"code","source":"# Load all data\nngs_16_pre = pd.read_csv(\"../input/NGS-2016-pre.csv\")\nngs_16_reg_1_6 = pd.read_csv(\"../input/NGS-2016-reg-wk1-6.csv\")\nngs_16_reg_7_12 = pd.read_csv(\"../input/NGS-2016-reg-wk7-12.csv\")\nngs_16_reg_13_17 = pd.read_csv(\"../input/NGS-2016-reg-wk13-17.csv\")\nngs_17_pre = pd.read_csv(\"../input/NGS-2017-pre.csv\")\nngs_17_reg_1_6 = pd.read_csv(\"../input/NGS-2017-reg-wk1-6.csv\")\nngs_17_reg_7_12 = pd.read_csv(\"../input/NGS-2017-reg-wk7-12.csv\")\nngs_17_reg_13_17 = pd.read_csv(\"../input/NGS-2017-reg-wk13-17.csv\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"64ffafc60ba1b905983246e4cd86ef8ffe1db465"},"cell_type":"code","source":"# Load only concussion specific plays\nngs_all_data = pd.DataFrame()\n\ndef get_play_ngs(row):\n    year = row.Season_Year\n    season_type = row.Season_Type\n    week = row.Week\n    gamekey = row.GameKey\n    play_id = row.PlayID\n    player_id = row.GSISID_Injured\n    partner_id = row.Primary_Partner_GSISID\n\n    if year == 2016:\n        if season_type == \"Pre\":\n            ngs_data = ngs_16_pre.loc[(ngs_16_pre[\"GameKey\"] == gamekey) & (ngs_16_pre[\"PlayID\"] == play_id) & ((ngs_16_pre[\"GSISID\"] == player_id) | (ngs_16_pre[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n        elif season_type == \"Reg\":\n            if (week >= 1) & (week <= 6):\n                ngs_data = ngs_16_reg_1_6.loc[(ngs_16_reg_1_6[\"GameKey\"] == gamekey) & (ngs_16_reg_1_6[\"PlayID\"] == play_id) & ((ngs_16_reg_1_6[\"GSISID\"] == player_id) | (ngs_16_reg_1_6[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n            elif (week >= 7) & (week <= 12):\n                ngs_data = ngs_16_reg_7_12.loc[(ngs_16_reg_7_12[\"GameKey\"] == gamekey) & (ngs_16_reg_7_12[\"PlayID\"] == play_id) & ((ngs_16_reg_7_12[\"GSISID\"] == player_id) | (ngs_16_reg_7_12[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n            elif (week >= 13) & (week <= 17):\n                ngs_data = ngs_16_reg_13_17.loc[(ngs_16_reg_13_17[\"GameKey\"] == gamekey) & (ngs_16_reg_13_17[\"PlayID\"] == play_id) & ((ngs_16_reg_13_17[\"GSISID\"] == player_id) | (ngs_16_reg_13_17[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n    elif year == 2017:\n        if season_type == \"Pre\":\n            ngs_data = ngs_17_pre.loc[(ngs_17_pre[\"GameKey\"] == gamekey) & (ngs_17_pre[\"PlayID\"] == play_id) & ((ngs_17_pre[\"GSISID\"] == player_id) | (ngs_17_pre[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n        elif season_type == \"Reg\":\n            if (week >= 1) & (week <= 6):\n                ngs_data = ngs_17_reg_1_6.loc[(ngs_17_reg_1_6[\"GameKey\"] == gamekey) & (ngs_17_reg_1_6[\"PlayID\"] == play_id) & ((ngs_17_reg_1_6[\"GSISID\"] == player_id) | (ngs_17_reg_1_6[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n            elif (week >= 7) & (week <= 12):\n                ngs_data = ngs_17_reg_7_12.loc[(ngs_17_reg_7_12[\"GameKey\"] == gamekey) & (ngs_17_reg_7_12[\"PlayID\"] == play_id) & ((ngs_17_reg_7_12[\"GSISID\"] == player_id) | (ngs_17_reg_7_12[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n            elif (week >= 13) & (week <= 17):\n                ngs_data = ngs_17_reg_13_17.loc[(ngs_17_reg_13_17[\"GameKey\"] == gamekey) & (ngs_17_reg_13_17[\"PlayID\"] == play_id) & ((ngs_17_reg_13_17[\"GSISID\"] == player_id) | (ngs_17_reg_13_17[\"GSISID\"] == partner_id))].sort_values(by = \"Time\")\n                \n    ngs_data.Time = ngs_data.Time.astype(\"datetime64\")\n    ball_snap = ngs_data.loc[(ngs_data.Event == \"ball_snap\")][\"Time\"].iloc[0]\n    \n    return ngs_data.loc[ngs_data.Time >= ball_snap]\n\nfor row in concussion_data.itertuples():\n    ngs_all_data = ngs_all_data.append(get_play_ngs(row))\n\nngs_all_data.head(3)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4cf2a00bf6b444421e477cce969e7e9381cb5cd3"},"cell_type":"markdown","source":"<hr />\n**Data visualization for plays with tackle event**<br />\nIt's hard to determine exactly when the concussion occurred, so let's use the data from the plays that have \"tackle\" event recorded.\n* Purple lines indicate the injured player.\n* Yellow lines indicate the primary parter."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"80499b2983651338f8c5dff58dbd9d57a8fd91b4"},"cell_type":"code","source":"# Calculate speed\ndef add_speed(row):\n    # Multiply by 0.9144 to convert yards to meters\n    row[\"Speed m/s\"] = row.dis * 0.9144 / 0.1\n    return row\n\nngs_all_data = ngs_all_data.apply(add_speed, axis = \"columns\")\n\n# Draw the graphics\nfor row in concussion_data.itertuples():\n    game_key = row.GameKey\n    play_id = row.PlayID\n    player_id = row.GSISID_Injured\n    partner_id = row.Primary_Partner_GSISID\n        \n    player_positions = ngs_all_data.loc[(ngs_all_data[\"GameKey\"] == game_key) & (ngs_all_data[\"PlayID\"] == play_id) & (ngs_all_data[\"GSISID\"] == player_id)].sort_values(by = \"Time\").reset_index()\n    partner_positions = ngs_all_data.loc[(ngs_all_data[\"GameKey\"] == game_key) & (ngs_all_data[\"PlayID\"] == play_id) & (ngs_all_data[\"GSISID\"] == partner_id)].sort_values(by = \"Time\").reset_index()\n    tackle_time = player_positions[(player_positions.Event == \"tackle\")].Time\n\n    if tackle_time.empty:\n        continue\n    else:\n        player_positions = player_positions.loc[player_positions[\"Time\"] <=  tackle_time.iloc[0]]\n        player_x = player_positions[\"x\"]\n        player_y = player_positions[\"y\"]\n        player_speed = player_positions[\"Speed m/s\"]\n        \n        # Configure graph\n        sns.set()\n        fig = plt.figure(figsize = (7, 3))\n        ax = fig.add_subplot(111)\n        ax.patch.set_facecolor(\"green\")\n\n        if not partner_positions.empty:\n            partner_positions = partner_positions.loc[partner_positions[\"Time\"] <=  tackle_time.iloc[0]]\n            partner_x = partner_positions[\"x\"]\n            partner_y = partner_positions[\"y\"]\n            partner_speed = partner_positions[\"Speed m/s\"]\n            cmap = plt.get_cmap('summer')\n            plt.scatter(partner_x, partner_y, c = partner_speed, cmap = cmap)\n        \n        cmap = plt.get_cmap('PuRd')\n        plt.scatter(player_x, player_y, c = player_speed, cmap = cmap)\n        \n        plt.clim(0, 12)\n        plt.colorbar(label = \"Speed (m/s)\")\n        plt.xlim(0, 120)\n        plt.xticks(np.arange(0, 120, step = 10), [\"\", \"G\", \"10\", \"20\", \"30\", \"40\", \"50\", \"40\", \"30\", \"20\", \"10\", \"G\"])\n        plt.ylim(-5, 59) # short side of the field is 53.3\n        plt.yticks(np.arange(0, 59, 53.3))\n        ax.set_title(row[-5] + \"  \" + row.Role_Injured + \" - \" + row.Player_Team + \"-\" + row.Number_Injured, fontsize = 12)\n        plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b626984fa010203532935bf60afdc518094eecf9"},"cell_type":"markdown","source":"<hr />**Since we don't have a precise time of the concussion causing hit, let's calculate the maximum speed in 1 second leading to the tackle event**"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"2de708c25424ea74311b9b5d22adc1548e34d777"},"cell_type":"code","source":"#Let's get the max speed in the last second leading to the tackle\ndef get_max_speed(row):\n    game_key = row.GameKey\n    play_id = row.PlayID\n    player_id = row.GSISID_Injured\n    partner_id = row.Primary_Partner_GSISID\n    max_speed_player = 0\n    max_speed_partner = 0\n\n    player_positions = ngs_all_data.loc[(ngs_all_data.GameKey == game_key) & (ngs_all_data.PlayID == play_id) & (ngs_all_data.GSISID == player_id)]\n    partner_positions = ngs_all_data.loc[(ngs_all_data.GameKey == game_key) & (ngs_all_data.PlayID == play_id) & (ngs_all_data.GSISID == partner_id)]\n    tackle_time = player_positions[(player_positions.Event == \"tackle\")].Time\n\n    if not tackle_time.empty:\n        tackle_time = tackle_time.iloc[0]\n        player_positions = player_positions.loc[(player_positions.Time <= tackle_time) & (player_positions.Time >= tackle_time + datetime.timedelta(seconds = -1))]\n        max_speed_player = player_positions[\"Speed m/s\"].max()\n        \n        if not partner_positions.empty:\n            partner_positions = partner_positions.loc[(partner_positions.Time <= tackle_time) & (partner_positions.Time >= tackle_time + datetime.timedelta(seconds = -1))]\n            max_speed_partner = partner_positions[\"Speed m/s\"].max()    \n    \n    row[\"Speed_Player\"] = max_speed_player\n    row[\"Speed_Partner\"] = max_speed_partner\n    \n    return row\n\nconcussion_data = concussion_data.apply(get_max_speed, axis = \"columns\")\n\nspeed_df = concussion_data.loc[concussion_data.Speed_Player > 0].loc[:, [\"GSISID_Injured\", \"Speed_Player\", \"Primary_Partner_GSISID\", \"Speed_Partner\"]].sort_values(by = \"Speed_Player\", ascending = False)\nspeed_df.columns = [\"Injured_Player_GSISID\", \"Speed_Player\", \"Partner_GSISID\", \"Speed_Partner\"]\nspeed_df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c30d87d2b7a5e8db9d59f35e74a4a8cf2681ca88"},"cell_type":"markdown","source":"The results are to variable to reach a definitive conclusion of the speed as a factor and the dataset is small.\n<hr />"},{"metadata":{"trusted":true,"_uuid":"a823553b5a3c16fee2db216682e523dccf11f097"},"cell_type":"markdown","source":""}],"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}