{"cells":[{"metadata":{"_uuid":"7005d049d0c5732c8252a8ba9fd71f0c0b7797cc"},"cell_type":"markdown","source":"**NFL Punt Analytics Rule Proposal**\nThere were 6681 punt plays run throughout the course of the 2016 and 2017 seasons combined. 37 of these punt plays resulted in a concussion at a rate of .554%, higher than most other types of NFL plays. Through the analysis of every punt play (pre, regular, postseason) from these two years, I have created a proposal of a rule change to limit concussions and increase player safety overall while not compromising the integrity of the game."},{"metadata":{"_kg_hide-output":false,"trusted":true,"_uuid":"df89778d24b1a605eef91347d97e4bb0609df45a","_kg_hide-input":true},"cell_type":"code","source":"# Kaggle NFL Punt Analytics Competition\n# by Nicholas Nigro\n# January 9, 2019\n\n#load packages\nlibrary(data.table)\nlibrary(ggthemes)\nlibrary(gridExtra)\nlibrary(stringr)\nlibrary(ggplot2)\nlibrary(scales)\n\n#import datasets\ngame_data <- read.csv(\"../input/game_data.csv\", header = TRUE)\nplay_information <- read.csv(\"../input/play_information.csv\", header = TRUE)\nplay_player_role_data <- read.csv(\"../input/play_player_role_data.csv\", header = TRUE)\nplayer_punt_data <- read.csv(\"../input/player_punt_data.csv\", header = TRUE)\nvideo_footage_control <- read.csv(\"../input/video_footage-control.csv\", header = TRUE)\nvideo_footage_injury <- read.csv(\"../input/video_footage-injury.csv\", header = TRUE)\nvideo_review <- read.csv(\"../input/video_review.csv\", header = TRUE)\n\n#merge datasets and create variables UniqueGameID and UniquePlayerID to be able to refer to players and plays uniquely\nplayer_punt_data_nonum <- unique(subset(player_punt_data, select = c(GSISID, Position)))\nplay_information$UniqueGameID <- paste(play_information$GameKey, play_information$PlayID)\nvideo_review$UniqueGameID <- paste(video_review$GameKey, video_review$PlayID)\nplay_information$Concussion <- (play_information$UniqueGameID %in% video_review$UniqueGameID)\nvideo_footage_injury$UniqueGameID <- paste(video_footage_injury$gamekey, video_footage_injury$playid)\nplay_player_role_data$UniqueGameID <- paste(play_player_role_data$GameKey, play_player_role_data$PlayID)\nplay_player_role_data$UniquePlayerID <- paste(play_player_role_data$UniqueGameID, play_player_role_data$GSISID)\nfull_player_data <- merge(player_punt_data_nonum, play_player_role_data, by = \"GSISID\")\nfull_video_injury <- merge(video_review, video_footage_injury, by = \"UniqueGameID\")\nfull_video_injury$UniquePlayerID <- paste(full_video_injury$UniqueGameID, full_video_injury$GSISID)\nfull_video_injury$UniqueOppPlayerID <- paste(full_video_injury$UniqueGameID, full_video_injury$Primary_Partner_GSISID)\nfull_injury <- merge(full_player_data, full_video_injury, by = \"UniquePlayerID\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"fd201ca51091d0162b83630bcbb0c12ec0b5ff19"},"cell_type":"code","source":"#bar plot analyzing concussion player's impact type\nggplot(full_injury, aes(x = Primary_Impact_Type)) +\n  geom_bar(width = 0.5,color=\"darkblue\") +\n  aes(fill = Primary_Impact_Type) +\n  theme(text = element_text(size=10),axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0))+\n  geom_text(stat='count', aes(label=..count..), hjust=0.5 , vjust=-0.5, size = 5) +\n  ggtitle(\"Impact on Player's Helmet Causing Concussion\") +\n  xlab(\"Impact Type\") +\n  ylab(\"Total Count\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"909e4539780d8df8e15784c6417a1f4894c41930"},"cell_type":"markdown","source":"The first notable data that I analyzed is shown in the plot above. At least 34 out of 37 concussions on punt plays in the past two years have occurred through helmet-to-player contact. Helmet-to-ground still occurs, but at a much lower rate, so I chose to investigate helmet-to-player collisions.\n\n**Current NFL Helmet Rule**\nRule 12 Section 2 Article 8 of the NFL Rulebook states: \n    “It is a foul if a player lowers his head to initiate and make contact with his helmet against an opponent.”\n    \nThis was a new rule implemented for the 2018. As the scope of this analysis is focused on solely the 2016 and 2017 data, since the 2018 season is not complete yet and the data is not available, we are not able to determine the impact of this rule. It is likely the fear of a 15 yard penalty and possible player ejection reduced the number of helmet to body/helmet impacts on punts in 2018 and will continue to help in future years. If the Helmet Rule were in effect in the past two seasons, thenumber of concussions probably would have been reduced.\n\nThis rule can be called on offensive or defensive players and also away from the ball on blockers, so it covers the full range of player activities that concussions have occurred on in the past two years as shown in the figure below. The Helmet Rule is a good starting point to reduce concussions on punts, but it is not the overall answer as some players will still make contact with their helmet despite this rule. So, we must continue our analysis. It is notable that all four activities listed in the figure have lead to multiple concussions per year on punts, so we must not focus on solely one of these activities, but instead explore all activities and plays as a whole."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"fdf901666225f1d7fc12b6b28d7e5513b09d24dd"},"cell_type":"code","source":"#bar plot analyzing concussion player's activity\nggplot(full_injury, aes(x = Player_Activity_Derived)) +\n  geom_bar(width = 0.5,color=\"darkblue\") +\n  aes(fill = Player_Activity_Derived) +\n  theme(text = element_text(size=10))+\n  geom_text(stat='count', aes(label=..count..), hjust=0.5 , vjust=-0.5, size = 5) +\n  ggtitle(\"Injured Player's Activity when Concussion was Received\") +\n  xlab(\"Player Activity\") +\n  ylab(\"Total Count\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true,"_uuid":"36f67f58f6ec62fc2c73d037d8b0d283f93a3863"},"cell_type":"code","source":"#extra analysis of other bar plots that were considered during research and investigation\n#bar plot analyzing concussion player's activity and impact type\nggplot(full_injury, aes(x = Player_Activity_Derived)) +\n  geom_bar(width = 0.5,color=\"darkblue\") +\n  facet_wrap(~Primary_Impact_Type) +\n  aes(fill = Player_Activity_Derived) +\n  ggtitle(\"Player Activity During Concussion\") +\n  xlab(\"Player Activity\") +\n  ylab(\"Total Count\")\n#bar plot analyzing concussion player's activity and impact type\nggplot(full_injury, aes(x = Primary_Impact_Type)) +\n  geom_bar(width = 0.5,color=\"darkblue\") +\n  facet_wrap(~Player_Activity_Derived) +\n  aes(fill = Primary_Impact_Type) +\n  theme(text = element_text(size=10),axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0))+\n  ggtitle(\"Activity During Concussion\") +\n  xlab(\"Helmet Impact\") +\n  ylab(\"Total Count\")\n#bar plot analyzing concussion player's position\nggplot(full_injury, aes(x = Position)) +\n  geom_bar(width = 0.5,color=\"darkblue\") +\n  facet_wrap(~Player_Activity_Derived) +\n  aes(fill = Position) +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0)) +\n  ggtitle(\"Position for Concussions\") +\n  xlab(\"Position\") +\n  ylab(\"Total Count\")\n#bar plot analyzing concussion player's role and activity\nggplot(full_injury, aes(x = Role)) +\n  geom_bar(width = 0.5,color=\"darkblue\") +\n  facet_wrap(~Player_Activity_Derived) +\n  aes(fill = Role) +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0)) +\n  ggtitle(\"Player Role for Concussions\") +\n  xlab(\"Role\") +\n  ylab(\"Total Count\")\n#bar plot analyzing concussion player's role\nggplot(full_injury, aes(x = Role)) +\n  geom_bar(width = 0.5,color=\"red\",fill=\"darkblue\") +\n  ggtitle(\"Player Role for Concussions\") +\n  xlab(\"Role\") +\n  ylab(\"Total Count\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"92921c9b9f3d27e611c05a6a54f19fc5330187a1"},"cell_type":"markdown","source":"**Frequency of Player Roles in Formation for All Punt Plays Against Punt Plays that Result in Concussions**\n\nNext, I took a look at the percent of the time of a role being in formation on a concussion play vs. any punt play. The most notable difference in percentages between roles are that there are more likely to be multiple sideline blockers (both VLi and VLo, both VRi and VRo) instead of just one blocker (VL, VR) for the punt return team on concussion plays compared to any punt play. Multiple blockers are present on 35% of all punts, while multiple blockers are present on about 50% of punts where concussions occur. This is the most prominent percentage difference for any role between concussive plays and all punt plays as shown in the figure below. Having two blockers lined up in formation on the speedy coverage team gunners (GR and GL) leads to concussions and we need further exploration to understand why.\n\n\n"},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true,"_uuid":"6a6ea8923e81208fab5c72beb4dcc2b924cf8425"},"cell_type":"code","source":"#order dataset by play and then by role\nplay_player_role_data_order <- play_player_role_data[order(play_player_role_data$UniqueGameID, play_player_role_data$Role),]\n#create formations dataset of all combinations of roles on the field on a play\nformations <- aggregate(Role ~ UniqueGameID, data = play_player_role_data_order, paste, collapse = \" \")\ncolnames(formations) <- c('UniqueGameID','Formation')\n#merge datasets to include play information and concussion tag on formations\nformations <- merge(play_information, formations, by='UniqueGameID')\nformations$ConcussionBinary <- ifelse(formations$Concussion == TRUE,1,0)\n#isolate  formations that cause concussions\nconcussion_formations <- aggregate(UniqueGameID ~ Formation, formations, function(x) length(unique(x)))\nconcussion_formations2 <- aggregate(ConcussionBinary ~ Formation, formations, mean)\nconcussion_formations <- merge(concussion_formations, concussion_formations2, by='Formation')\ncolnames(concussion_formations) <- c('Formation','Total_Count','Concussion_Percentage')\n#split formations so each role has its own column in the dataset\nconcussion_formations3 <- as.data.table(str_split_fixed(concussion_formations$Formation, \" \", 24))\nconcussion_formations <- cbind(concussion_formations,concussion_formations3)\nconcussion_formations$Concussion_count <- concussion_formations$Total_Count*concussion_formations$Concussion_Percentage\nconcussion_formations_order <- concussion_formations[order(-concussion_formations$Concussion_count),]\n#adding rows for the formations that have multiple concussions so duplicates are counted correctly\nconcussion_formations_order <- rbind(concussion_formations_order, concussion_formations_order[1:2,], concussion_formations_order[1:6,])\nconcussion_formations_order <- concussion_formations_order[order(-concussion_formations_order$Concussion_count),]\n#create datasets that are easy to grab from for plotting\nconcuss_plot_pre = cbind(concussion_formations_order[1:37,paste(\"V\", 1:24, sep=\"\")])\nconcuss_plot <- data.frame(V1=unlist(concuss_plot_pre[,1:24], use.names = FALSE))\n#remove blanks\nconcuss_plot[concuss_plot==\"\"] <- NA\nconcuss_plot <- na.omit(concuss_plot)\n\n#plot player roles on the field for all punt plays\nggplot(play_player_role_data, aes(x = Role)) +\n  geom_bar(width = .5,color=\"red\",fill=\"darkblue\") +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0)) +\n  geom_text(stat='count', aes(label=..count..), angle = -90, hjust=1, vjust=0) +\n  ggtitle(\"Player Roles\") +\n  xlab(\"Role\") +\n  ylab(\"Total Count\")\n\n#plot player roles on the field for concussion plays\nggplot(concuss_plot, aes(x = V1)) +\n  geom_bar(width = .5,color=\"red\",fill=\"darkblue\") +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0)) +\n  geom_text(stat='count', aes(label=..count..), angle = -90, hjust=1 , vjust=0) +\n  ggtitle(\"Player Roles in Concussion Plays\") +\n  xlab(\"Role\") +\n  ylab(\"Total Count\")\n\n#now we want to look at the differences between player roles on concussion plays and on every punt play\n#first need percentage of time each role is in formation for concussion plays\nconcussion_counts <- aggregate(data.frame(count = concuss_plot$V1), list(Role = concuss_plot$V1), length)\nconcussion_counts$percent <- round(100*concussion_counts$count/length(concuss_plot_pre$V1), digits = 2)\n#percentage of time each role is in formation for all punt plays\ntotal_counts <- aggregate(data.frame(totalcount = play_player_role_data$Role), list(Role = play_player_role_data$Role), length)\ntotal_counts$totalpercent <- round(100*total_counts$totalcount/length(formations$Formation), digits = 2)\n#merge the percentages into one dataset\nconcussion_counts <- merge(concussion_counts, total_counts, by = \"Role\")\n#find difference between percentages for each role\nconcussion_counts$difference <- round(concussion_counts$percent - concussion_counts$totalpercent, digits = 2)\n#calculate percent difference of the percentages for each role\nconcussion_counts$percdifference <- round(concussion_counts$difference / ((concussion_counts$totalpercent+concussion_counts$percent)/2), digits=2)*100\n\n#plot player roles' percentages on the field for concussion plays\nggplot(concussion_counts, aes(x = Role, y = percent)) +\n  geom_bar(stat = \"identity\", width = .5,color=\"red\",fill=\"darkblue\") +\n  geom_text(aes(label=percent), angle = -90, vjust=0, hjust=1) +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0), text = element_text(size=10)) +\n  ggtitle(\"Player Roles on the Field in Concussion Plays\") +\n  xlab(\"Role\") +\n  ylab(\"Percent\")\n\n#plot player roles' percentages on the field for all punt plays\nggplot(concussion_counts, aes(x = Role, y = totalpercent)) +\n  geom_bar(stat = \"identity\", width = .5,color=\"red\",fill=\"darkblue\") +\n  geom_text(aes(label=totalpercent), angle = -90, vjust=0, hjust=1) +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0), text = element_text(size=10)) +\n  ggtitle(\"Player Roles on the Field in All Plays\") +\n  xlab(\"Role\") +\n  ylab(\"Percent\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"34e3fbd9ac929b15bbf5b7225fbca066c58648ad"},"cell_type":"code","source":"#plot difference in percentages of player roles on the field for all punt plays vs concussion plays\nggplot(concussion_counts, aes(x = Role, y = difference)) +\n  geom_bar(stat = \"identity\", width = .5,color=\"red\",fill=\"red\") +\n  geom_text(aes(label=difference), angle = -90, vjust=.3, hjust=1, size = 5, color=\"darkblue\") +\n  theme(text = element_text(size=20))+\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0), text = element_text(size=10)) +\n  ggtitle(\"Difference in Percentages for Player Roles for Concussion Plays vs. All Plays\") +\n  xlab(\"Role\") +\n  ylab(\"Difference in Percentages\")+\n  labs(caption = \"*Positive Values Indicate Role More Likely on the Field on Concussion Plays\")\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"507ed04380ca4aeb6e4e76b3a4663bf079bbd393"},"cell_type":"markdown","source":"The figure below completes a percent difference calculation on the difference in percentages. The percent difference calculation is as follows for each player role:\n (difference in concussion percentage and all punt play percentage)/(sum of concussion percentage and all punt play percentage/2)*100\n \n It's interesting to note that the presence of PFB is actually the largest difference maker in a concussive play based on the percent difference calculation and not the gunner blockers. The PFB is used in less than 5% of all punt plays, which leads to a small sample size, but still shows the highest correlation with a concussion occurring on a punt."},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"8ae4e4d63c8f0f71d554d248c4e0281173f73330"},"cell_type":"code","source":"#plot percent difference calculation of player roles on the field for all punt plays vs concussion plays\nggplot(concussion_counts, aes(x = Role, y = percdifference)) +\n  geom_bar(stat = \"identity\", width = .5,color=\"red\",fill=\"red\") +\n  geom_text(aes(label=percdifference), angle = -90, vjust=.3, hjust=1,color=\"darkblue\") +\n  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0), text = element_text(size=10)) +\n  ggtitle(\"Percent Difference Calculation for Player Roles on the Field for Concussion Plays Against All Plays\") +\n  xlab(\"Role\") +\n  ylab(\"Percent Difference\")+\n  labs(caption = \"*Positive Values Indicate Role More Likely on the Field on Concussion Plays\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3acd2cc0bd338cf3fae5e076caa732a2bff8eb49"},"cell_type":"markdown","source":"**Number of Interior Coverage Team Players in Formation Against Number of Interior Return Team Players in Formation**\nAn interior player on the coverage team is anyone except the gunners (GR, GL, etc.) and the punter (P). An interior player on the return team is anyone except the gunner blockers (VR, VL, etc.), blocker near punt returner (PFB), and punt returner (PR). Over 99% of all punt plays (including all 37 concussion plays) had 8 interior players for the coverage team. The percentage of interior players for the return team varies usually between 6, 7, or 8 players. This leads to the coverage team either having 1 or 2 extra interior players, or the two teams have the same amount of interior players. The series of figures below illustrate the differences in interior players on both the coverage team and return team for concussion plays and all punt plays. There is a clear trend that having an equal number of players on the interior for both teams leads to less concussions, while having more players on the interior on the coverage team than the return team leads to more concussions. \n\nA 2-sample t-test comparing concussion punt plays to all punt plays found it statistically significant at the 95% confidence level that the mean number of additional interior players for the coverage team over the return team was larger for the concussion group (p-value = .0084). ","attachments":{}},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"14a4a93ed378b83d6892e1859d098b1131e130af"},"cell_type":"code","source":"#group player roles into categories for offense/defense and inside/outside/back based on location on the field for each play\n#do this for both concussion plays and separately for all plays\nconcuss_plot_pre$offinside <- rowSums(concuss_plot_pre == \"PLW\")+rowSums(concuss_plot_pre == \"PLT\")+ rowSums(concuss_plot_pre == \"PLG\")+rowSums(concuss_plot_pre == \"PLS\")+ rowSums(concuss_plot_pre == \"PRG\")+ rowSums(concuss_plot_pre == \"PRT\")+ rowSums(concuss_plot_pre == \"PRW\")+ rowSums(concuss_plot_pre == \"PPR\")+ rowSums(concuss_plot_pre == \"PPL\")+ rowSums(concuss_plot_pre == \"PPRo\")+ rowSums(concuss_plot_pre == \"PPRi\")+ rowSums(concuss_plot_pre == \"PPLo\")+ rowSums(concuss_plot_pre == \"PPLi\")\nconcuss_plot_pre$offoutside <- rowSums(concuss_plot_pre == \"GL\")+rowSums(concuss_plot_pre == \"GLo\")+rowSums(concuss_plot_pre == \"GLi\")+rowSums(concuss_plot_pre == \"GR\")+rowSums(concuss_plot_pre == \"GRi\")+rowSums(concuss_plot_pre == \"GRo\")\nconcuss_plot_pre$definside <- rowSums(concuss_plot_pre == \"PDR1\")+rowSums(concuss_plot_pre == \"PDR2\")+rowSums(concuss_plot_pre == \"PDR3\")+rowSums(concuss_plot_pre == \"PDR4\")+rowSums(concuss_plot_pre == \"PDR5\")+rowSums(concuss_plot_pre == \"PDR6\")+rowSums(concuss_plot_pre == \"PDL1\")+rowSums(concuss_plot_pre == \"PDL2\")+rowSums(concuss_plot_pre == \"PDL3\")+rowSums(concuss_plot_pre == \"PDL4\")+rowSums(concuss_plot_pre == \"PDL5\")+rowSums(concuss_plot_pre == \"PDL6\")+rowSums(concuss_plot_pre == \"PLR\")+rowSums(concuss_plot_pre == \"PLL\")+rowSums(concuss_plot_pre == \"PLM\")+rowSums(concuss_plot_pre == \"PLR1\")+rowSums(concuss_plot_pre == \"PLR2\")+rowSums(concuss_plot_pre == \"PLR3\")+rowSums(concuss_plot_pre == \"PLL1\")+rowSums(concuss_plot_pre == \"PLL2\")+rowSums(concuss_plot_pre == \"PLL3\")+rowSums(concuss_plot_pre == \"PLM1\")\nconcuss_plot_pre$defback <- rowSums(concuss_plot_pre == \"PR\")+rowSums(concuss_plot_pre == \"PFB\")\nconcuss_plot_pre$defoutside <- rowSums(concuss_plot_pre == \"VL\")+rowSums(concuss_plot_pre == \"VR\")+rowSums(concuss_plot_pre == \"VLi\")+rowSums(concuss_plot_pre == \"VLo\")+rowSums(concuss_plot_pre == \"VRi\")+rowSums(concuss_plot_pre == \"VRo\")\nall_formation_positions = as.data.table(str_split_fixed(formations$Formation, \" \", 24))\nall_formation_positions$offinside <- rowSums( all_formation_positions == \"PLW\")+rowSums( all_formation_positions == \"PLT\")+ rowSums( all_formation_positions == \"PLG\")+rowSums( all_formation_positions == \"PLS\")+ rowSums( all_formation_positions == \"PRG\")+ rowSums( all_formation_positions == \"PRT\")+ rowSums( all_formation_positions == \"PRW\")+ rowSums( all_formation_positions == \"PPR\")+ rowSums( all_formation_positions == \"PPL\")+ rowSums( all_formation_positions == \"PPRo\")+ rowSums( all_formation_positions == \"PPRi\")+ rowSums( all_formation_positions == \"PPLo\")+ rowSums( all_formation_positions == \"PPLi\")+rowSums( all_formation_positions == \"PC\")\nall_formation_positions$offoutside <- rowSums( all_formation_positions == \"GL\")+rowSums( all_formation_positions == \"GLo\")+rowSums( all_formation_positions == \"GLi\")+rowSums( all_formation_positions == \"GR\")+rowSums( all_formation_positions == \"GRi\")+rowSums( all_formation_positions == \"GRo\")\nall_formation_positions$definside <- rowSums( all_formation_positions == \"PDR1\")+rowSums( all_formation_positions == \"PDR2\")+rowSums( all_formation_positions == \"PDR3\")+rowSums( all_formation_positions == \"PDR4\")+rowSums( all_formation_positions == \"PDR5\")+rowSums( all_formation_positions == \"PDR6\")+rowSums( all_formation_positions == \"PDL1\")+rowSums( all_formation_positions == \"PDL2\")+rowSums( all_formation_positions == \"PDL3\")+rowSums( all_formation_positions == \"PDL4\")+rowSums( all_formation_positions == \"PDL5\")+rowSums( all_formation_positions == \"PDL6\")+rowSums( all_formation_positions == \"PLR\")+rowSums( all_formation_positions == \"PLL\")+rowSums( all_formation_positions == \"PLM\")+rowSums( all_formation_positions == \"PLR1\")+rowSums( all_formation_positions == \"PLR2\")+rowSums( all_formation_positions == \"PLR3\")+rowSums( all_formation_positions == \"PLL1\")+rowSums( all_formation_positions == \"PLL2\")+rowSums( all_formation_positions == \"PLL3\")+rowSums( all_formation_positions == \"PLM1\")\nall_formation_positions$defback <- rowSums( all_formation_positions == \"PR\")+rowSums( all_formation_positions == \"PFB\")\nall_formation_positions$defoutside <- rowSums( all_formation_positions == \"VL\")+rowSums( all_formation_positions == \"VR\")+rowSums( all_formation_positions == \"VLi\")+rowSums( all_formation_positions == \"VLo\")+rowSums( all_formation_positions == \"VRi\")+rowSums( all_formation_positions == \"VRo\")\n#find difference in inside players for offense and defense on both concussion and all plays\nconcuss_plot_pre$interiordiff <- concuss_plot_pre$offinside - concuss_plot_pre$definside\nall_formation_positions$interiordiff <-  all_formation_positions$offinside -  all_formation_positions$definside\n#run t test determining whether there is a difference between the groups of concussion plays and all plays for the mean interior difference of players between coverage and return teams\nt.test(concuss_plot_pre$interiordiff,all_formation_positions$interiordiff,alternative=\"greater\")\n\n#create pie chart showing interior player differences on concussion plays\ncpie_summary = as.data.table(table(concuss_plot_pre$interiordiff))\ncolnames(cpie_summary) <- c('Additional_Interior_Kicking_Team','Count')\ncpie_summary$perc = percent(round(cpie_summary$Count/sum(cpie_summary$Count), digits = 4))\ncpie_summary=rbind(cpie_summary[1:3,], data.frame(Additional_Interior_Kicking_Team='Others', Count = 0, perc = percent(0)))\nggplot(cpie_summary, aes(x=\"\", y = Count, fill = Additional_Interior_Kicking_Team)) +\n  geom_bar(width = 1, stat = 'identity') +\n  geom_text(aes(x = \"\", label=cpie_summary$perc), size = 5, position = position_stack(vjust = .5))+\n  coord_polar(theta = \"y\", start = 0)+\n  theme(text = element_text(size=10))+\n  ggtitle(\"Interior Player Comparison in Concussion Plays\")\n\n#create pie chart showing interior player differences on all plays\nallpie_summary <- as.data.table(table(all_formation_positions$interiordiff))\ncolnames(allpie_summary) <- c('Additional_Interior_Kicking_Team','Count')\nallpie_summary$perc <- percent(round(allpie_summary$Count/sum(allpie_summary$Count), digits = 4))\nallpie_summary <- allpie_summary[order(-allpie_summary$Count)]\nallpie_summary <- rbind(allpie_summary[1:3,], data.frame(Additional_Interior_Kicking_Team='Others', Count = 126, perc = percent(.009)))\nggplot(allpie_summary, aes(x = \"\", y = Count, fill = Additional_Interior_Kicking_Team)) +\n  geom_bar(width = 1, stat = 'identity') +\n  geom_text(aes(x=\"\",label=allpie_summary$perc), size = 5, position = position_stack(vjust = .5))+\n  coord_polar(theta = 'y', start = 0)+\n  theme(text = element_text(size=10))+\n  ggtitle(\"Interior Player Comparison in All Plays\")\n\n#bar chart showing counts of number of return team interior players on all concussion plays\nggplot(concuss_plot_pre, aes(x = offinside)) +\n  geom_bar(width = 3, fill=\"darkblue\", color=\"red\") +\n  facet_wrap(~definside) +\n  scale_x_discrete(labels = \"\") +\n  theme(text = element_text(size=10)) +\n  geom_text(stat='count', aes(label=..count..), hjust=1, vjust=-.3, size=5) +\n  ggtitle(\"Number of Return Team Interior Players on the Field\") +\n  xlab(\"\") +\n  ylab(\"Total Count of Concussion Plays\")\n\n#bar chart showing counts of difference in interior players on all concussion plays\nggplot(concuss_plot_pre, aes(x = interiordiff)) +\n  geom_bar(width = .5, fill=\"darkblue\", color=\"red\") +\n  geom_text(stat='count', aes(label=..count..), hjust=1, vjust=-.3, size=5) +\n  theme(text = element_text(size=10)) +\n  ggtitle(\"Number of Extra Interior Players for Coverage Team Compared to Return Team\") +\n  xlab(\"Number of Additional Coverage Team Interior Players\") +\n  ylab(\"Total Count of Concussion Plays\")\n\n#bar chart showing counts of difference in interior players on all punt plays\nggplot( all_formation_positions, aes(x = interiordiff)) +\n  geom_bar(width = .5, fill=\"darkblue\", color=\"red\") +\n  geom_text(stat='count', aes(label=..count..), hjust=.5, vjust=0, size=5) +\n  theme(text = element_text(size=10)) +\n  aes(fill = interiordiff) +\n  ggtitle(\"Number of Extra Interior Players in Formation for Kicking Team Compared to Return Team\") +\n  xlab(\"Number of Additional Kicking Team Interior Players\") +\n  ylab(\"Total Count of All Plays\")\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"32b8f07b83117eddac1177b215d60ac8c2ad3130"},"cell_type":"markdown","source":"**Fair Catches**\nAn overwhelming majority (61.6%) of the time when a fair catch happens, the coverage team has an equal number of players on the interior compared to the return team. This is likely due to single teaming the gunners who can get down the field faster with only one blocker to get around in order to force the punt returner to call a fair catch. The full breakdown of the number of additional players on the coverage team interior on fair catch plays is shown in the figure below. A concussion occurred on a fair catch punt only .12% (2/1659) of the time in the past 2 years. A concussion occurred on a non-fair catch punt .70% (35/5022) of the time in the past 2 years. Therefore, it is 6 times more likely for a concussion to occur on a non-fair catch punt play compared to a fair catch. Forcing fair catches is a massive key to reducing concussions on punt plays, because plays are shorter in time, there is no tackling, and less blocking leading to less collisions overall. \n\nConcussions on fair catches:"},{"metadata":{"_kg_hide-input":true,"trusted":true,"_uuid":"c1ed896a298248c50d3309f8617bbfe757e2b64a"},"cell_type":"code","source":"#analyzing fair catch statistics, isolate all fair catch plays first\nfair_catch <- formations[which(str_detect(formations$PlayDescription, \"fair catch\")), ]\n#display how many fair catches had a concussion on their play\ntable(fair_catch$Concussion)\n#group player roles into categories for offense/defense and inside/outside/back based on location on the field for each fair catch play\nall_fair_catch_positions <- as.data.table(str_split_fixed(fair_catch$Formation, \" \", 24))\nall_fair_catch_positions$offinside <- rowSums(all_fair_catch_positions == \"PLW\")+rowSums( all_fair_catch_positions == \"PLT\")+ rowSums( all_fair_catch_positions == \"PLG\")+rowSums( all_fair_catch_positions == \"PLS\")+ rowSums( all_fair_catch_positions == \"PRG\")+ rowSums( all_fair_catch_positions == \"PRT\")+ rowSums( all_fair_catch_positions == \"PRW\")+ rowSums( all_fair_catch_positions == \"PPR\")+ rowSums( all_fair_catch_positions == \"PPL\")+ rowSums( all_fair_catch_positions == \"PPRo\")+ rowSums( all_fair_catch_positions == \"PPRi\")+ rowSums( all_fair_catch_positions == \"PPLo\")+ rowSums( all_fair_catch_positions == \"PPLi\")+rowSums( all_fair_catch_positions == \"PC\")\nall_fair_catch_positions$offoutside <- rowSums(all_fair_catch_positions == \"GL\")+rowSums( all_fair_catch_positions == \"GLo\")+rowSums( all_fair_catch_positions == \"GLi\")+rowSums( all_fair_catch_positions == \"GR\")+rowSums( all_fair_catch_positions == \"GRi\")+rowSums( all_fair_catch_positions == \"GRo\")\nall_fair_catch_positions$definside <- rowSums(all_fair_catch_positions == \"PDR1\")+rowSums( all_fair_catch_positions == \"PDR2\")+rowSums( all_fair_catch_positions == \"PDR3\")+rowSums( all_fair_catch_positions == \"PDR4\")+rowSums( all_fair_catch_positions == \"PDR5\")+rowSums( all_fair_catch_positions == \"PDR6\")+rowSums( all_fair_catch_positions == \"PDL1\")+rowSums( all_fair_catch_positions == \"PDL2\")+rowSums( all_fair_catch_positions == \"PDL3\")+rowSums( all_fair_catch_positions == \"PDL4\")+rowSums( all_fair_catch_positions == \"PDL5\")+rowSums( all_fair_catch_positions == \"PDL6\")+rowSums( all_fair_catch_positions == \"PLR\")+rowSums( all_fair_catch_positions == \"PLL\")+rowSums( all_fair_catch_positions == \"PLM\")+rowSums( all_fair_catch_positions == \"PLR1\")+rowSums( all_fair_catch_positions == \"PLR2\")+rowSums( all_fair_catch_positions == \"PLR3\")+rowSums( all_fair_catch_positions == \"PLL1\")+rowSums( all_fair_catch_positions == \"PLL2\")+rowSums( all_fair_catch_positions == \"PLL3\")+rowSums( all_fair_catch_positions == \"PLM1\")\nall_fair_catch_positions$defback <- rowSums(all_fair_catch_positions == \"PR\")+rowSums( all_fair_catch_positions == \"PFB\")\nall_fair_catch_positions$defoutside <- rowSums(all_fair_catch_positions == \"VL\")+rowSums( all_fair_catch_positions == \"VR\")+rowSums( all_fair_catch_positions == \"VLi\")+rowSums( all_fair_catch_positions == \"VLo\")+rowSums( all_fair_catch_positions == \"VRi\")+rowSums( all_fair_catch_positions == \"VRo\")\nall_fair_catch_positions$interiordiff <-  all_fair_catch_positions$offinside -  all_fair_catch_positions$definside\n#summarize interior difference counts on fair catch plays and set up for a pie chart\nfc_summary <- as.data.table(table(all_fair_catch_positions$interiordiff))\ncolnames(fc_summary) <- c('Additional_Interior_Kicking_Team','Count')\nfc_summary <- fc_summary[order(-fc_summary$Count)]\nfc_summary$perc <-  percent(round(fc_summary$Count/sum(fc_summary$Count), digits = 4))\nfc_summary <- rbind(fc_summary[1:3,], data.frame(Additional_Interior_Kicking_Team='Others', Count = 19, perc = percent(.012)))\n\n#create pie chart showing interior player differences on fair catch plays\nggplot(fc_summary, aes(x=\"\", y = Count, fill = Additional_Interior_Kicking_Team)) +\n  geom_bar(width = 1, stat = 'identity') +\n  coord_polar(theta = \"y\", start = 0)+\n  theme(text = element_text(size=10))+\n  geom_text(label=fc_summary$perc, size = 5)+\n  ggtitle(\"Interior Player Comparison on Fair Catch Plays \")\n  ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4fd13dcefa0af1fb2caebdfbf2082988212c7000"},"cell_type":"markdown","source":"**Rule Proposal**\nA rule could be amended to Rule 9 Section 1 Article 3 Item 1 in the NFL Rulebook for the defensive team punt formation as the 3rd statement.\n\nThe new rule would state as follows: \n\n\"Punt Formation. When Team A presents a punt formation:\n3) Team B must have a minimum of 8 players meet both of the following criteria at the snap:\n\ta) When ignoring the player closest to each sideline for Team A, Team B players must be closer to the far sideline or within 2 yards in the direction of the near sideline of at least one of the other Team A\tplayers.\n\tb) Within ten yards of the line of scrimmage.\n**Penalty: For illegal formation by the defense: Loss of five yards.** \"\n\nWith this new proposed rule change, the return team must keep 8 of their players within 2 yards towards the sideline of the punt coverage interior players, and within ten yards of the line of scrimmage. Over 99% of coverage team punt formations had 8 players towards the middle of the field and line of scrimmage, a punter, and a gunner on each sideline. The player closest to each sideline for the coverage team is ignored in this rule, since we want 8 players on the return team to be in formation in the middle of the field in the same vicinity as the 8 players on the interior on the coverage team.\nThe one player closest to each sideline is normally the gunner. The main purpose of the rule change is to stop the double teaming of the gunners on the coverage team, avoid having a second player back near the punt returner, and make an equal number of interior players on each side of the ball. This way the gunners can force more fair catches, and there will be a sufficient number of blockers on the interior return team to match up with the interior coverage team. \n\n**Integrity of the Game**\nWe don't want to drastically change the way NFL football is played. This is intended to be a simple formation rule change that forces more fair catches and increases player safety without altering much of the gameplay. I'll run through a few likely concerns and why the rule is worded in the manner that it is.\n\nFlexibility in punt return formation to match coverage team:\n“A minimum of 8 players” was chosen to allow for a punt returner and likely for a man to cover each gunner. Only the outermost player on each side on the coverage team is ignored for this rule, so if the coverage teams puts two gunners on the same side in order to try to get more pressure downfield or run a fake punt, the return team is able to cover and block this second gunner since one or more of the 8 players can move and line up near them. Essentially in this case one of the 8 \"interior\" players on the coverage team is actually lining up close to the sideline, allowing increased space for the return team to set up their formation and be able to cover towards the sideline.\n\nThe PFB:\nThis rule likely eliminates the use of the PFB (a man directly in front of or near the punt returner) since all 8 interior players must be within 10 yards of the line of scrimmage. If the punt coverage team has two gunners, the punt return team will likely have a man covering each gunner and then a punt returner with the remaining 8 players in the interior box created by the proposed rule. The sacrifice of the PFB is worth it since it was used in less than 5% of all punt plays and had a strong correlation with concussions when present on the field. A team could also still elect to use a PFB if they do not cover one of the gunners or in the case when the coverage team is not using a gunner on both sides. \n\nAttempts to still double cover gunners:\nThe 10 yards from line of scrimmage threshold was chosen to allow for sufficient space for all interior players to line up in formation, but not too large to allow players line up far off the line of scrimmage and at the edge of the formation in order run immediately towards the sideline to double team a gunner. This 10 yard threshold could be experimented with and changed to a smaller yardage value if players would still attempt this tactic, as this will most likely only lead to higher speed collisions.\n\nPunt blocks:\nThe “within 2 yards in the direction of the near sideline” language was added to limit how close to the gunners the interior return team players could get, but also allows for an opening on the outside of the interior coverage team players for edge rushers to be able to run around and attempt to block a punt. In no way is this rule attempting to limit the ability of the return team to block a punt, so the 2 yard language threshold could be raised if some players normally line up a little farther towards the near sideline when trying to block punts. \n\n**Conclusion**\nA new proposed rule change to the return team formation is a simple, logical rule that fits with the current rules of the NFL. This proposed rule would have at least 8 players on the return team closer to the center of the field or within 2 yards towards the near sideline than the second outermost player on each side of the coverage team, and within 10 yards of the line of scrimmage at the snap. The wording of this rule may be a mouthful, but it would reduce concussions on punt plays by forcing fair catches and having sufficient blockers of all coverage team players. Fair catches are shorter plays with no tackling, less blocking, and overall less collisions that reduce concussions and other injuries comapred normal punt plays. There would be an increase in fair catches, but still not a fair catch on every punt (a little less than half of punt plays single covering gunners result in fair catches) to still allow for some exciting punt returns. The rule wording allows for sufficient coverage of fake punt plays and unique coverage team formations in order to maintain the integrity of the game. If a balance of player safety and maintaining integrity of the game is the what the NFL is looking to add with a punt play rule change, a simple proposed formation rule like this one should be heavily considered.\n\nThank you for your time and consideration.","attachments":{}}],"metadata":{"kernelspec":{"display_name":"R","language":"R","name":"ir"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}