{"cells": [{"cell_type": "markdown", "metadata": {"_uuid": "9043778d42ebd3abef7c3a1ed24485db5cf2416d"}, "source": ["# Changes to incorporate when trying to reduce concussions on punt plays:\n", "\n", "1. Need to enforce stricter leading with helmet calls, so that players are not incentivized to lead with their helmet when tackling or blocking.\n", "2. Need to make slight modification to the standard punt formation rules that will reduce the velocity of the players to minimize chance of concussion occurring.\n", "\n", "\n", "The notebook below goes over the above proposals along with the corresponding analysis that supports these proposals."]}, {"cell_type": "code", "execution_count": 4, "metadata": {"_uuid": "bc4632a23e23456123283d485c73c530e5487684"}, "outputs": [], "source": ["import pandas as pd\n", "import numpy as np\n", "\n", "import math\n", "\n", "from scipy.stats import chisquare\n", "from scipy.stats import ttest_ind\n", "\n", "import datetime\n", "\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "\n", "from matplotlib  import cm\n", "import matplotlib.patches as patches\n", "\n", "from matplotlib.patches import Patch\n", "from matplotlib.lines import Line2D\n", "\n", "import os\n", "print(os.listdir(\"../input\"))\n", "\n", "from IPython.display import HTML\n", "from IPython.display import Image\n", "\n", "import warnings\n", "\n", "warnings.filterwarnings('ignore')"]}, {"cell_type": "markdown", "metadata": {"_uuid": "e6544309891f0191ed86150ba3fa7dbc01300fe2"}, "source": ["# Findings\n", "\n", "It was found that there are two main factors of concussion inducing plays on punt returns.\n", "\n", "* The dangerous form of blocking or tackling leading with the helmet\n", "* The faster velocity that occurs on punt-plays as opposed to the standard run or pass plays that are in a football game.\n", "\n", "The combination of both of these factors increase the probability of players experiencing a concussion.\n", "\n", "To change the player\u00e2\u20ac\u2122s behavior of leading with the helmet when they block or tackle, the NFL needs to enforce stricter penalties similar to the new targeting rules that college football has put in place.\n", "\n", "\n", "To reduce the average player velocity during a punt play, the traditional punt play formations for the returning and coverage team needs to be altered.\n", "\n", "* Only 4 players are allowed on or near the line of scrimmage by the ball snap location for each team, otherwise it would be called an illegal formation.\n", "\n", "Explanation for both of these rule changes are in the data analysis are in this notebook."]}, {"cell_type": "markdown", "metadata": {"_uuid": "05945e25e6c1f09d96c9dffc46380ec713340930"}, "source": ["# NGS Data Analysis of Video Review\n", "\n", "* Note: The concussion_inv dataset was created in the later part of the notebook, but for presentation purposes it needed to be uploaded as a private dataset to Kaggle Server"]}, {"cell_type": "code", "execution_count": 22, "metadata": {"_uuid": "1c144697fe5b06876d404c4451e8fb3678f75ed1", "collapsed": true}, "outputs": [], "source": ["involved_players=pd.read_csv('../input/user-input-data/concussion_inv.csv')\n", "\n", "\n", "ngs1=pd.read_csv('../input/NFL-Punt-Analytics-Competition/NGS-2016-reg-wk1-6.csv')\n", "ngs1_merge=pd.merge(ngs1,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])\n", "\n", "ngs2=pd.read_csv('../input/NFL-Punt-Analytics-Competition/NGS-2016-reg-wk7-12.csv')\n", "ngs2_merge=pd.merge(ngs2,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])\n", "\n", "ngs3=pd.read_csv('../input/NFL-Punt-Analytics-Competition/NGS-2016-reg-wk13-17.csv')\n", "ngs3_merge=pd.merge(ngs3,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])\n", "\n", "ngs4=pd.read_csv('../input/NFL-Punt-Analytics-Competition/NGS-2016-pre.csv')\n", "ngs4_merge=pd.merge(ngs4,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])\n", "\n", "ngs5=pd.read_csv('../input/NFL-Punt-Analytics-Competition/NGS-2016-post.csv')\n", "ngs5_merge=pd.merge(ngs5,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])\n", "\n", "ngs2_merge['Index']=np.arange(1036,len(ngs2_merge)+1036)\n", "ngs2_merge.set_index('Index',inplace=True)\n", "ngs_combined=pd.concat([ngs1_merge,ngs2_merge])\n", "\n", "ngs3_merge['Index']=np.arange(3058,len(ngs3_merge)+3058)\n", "ngs3_merge.set_index('Index',inplace=True)\n", "ngs_combined=pd.concat([ngs_combined,ngs3_merge])\n", "\n", "ngs4_merge['Index']=np.arange(8929,len(ngs4_merge)+8929)\n", "ngs4_merge.set_index('Index',inplace=True)\n", "ngs_combined=pd.concat([ngs_combined,ngs4_merge])\n", "\n", "ngs5_merge['Index']=np.arange(13390,len(ngs5_merge)+13390)\n", "ngs5_merge.set_index('Index',inplace=True)\n", "ngs_combined=pd.concat([ngs_combined,ngs5_merge])\n", "\n", "ngs_combined['Time']=ngs_combined.Time.map(lambda x:datetime.datetime.strptime(x,'%Y-%m-%d %H:%M:%S.%f'))"]}, {"cell_type": "markdown", "metadata": {"_uuid": "a6b84f58a7617bfa42d75140ebb754a18f02abbb"}, "source": ["## Plotting Player Motion with Velocities "]}, {"cell_type": "code", "execution_count": 25, "metadata": {"_uuid": "86afd8254b2df04696fab7264e9417b876c4900b", "collapsed": true, "hide_input": true, "hide_output": true}, "outputs": [], "source": ["#Functions used to plot NGS data along with velocity data to track concussion time\n", "\n", "def plot_ngs_data(df,season,gamekey,playid):\n", "    \n", "    filtered_df1=df[(df.Season_Year==season)&(df.GameKey==gamekey)&(df.PlayID==playid)]\n", "    \n", "    players=filtered_df1.GSISID.unique()\n", "    \n", "    player_1=players[0]\n", "    player_2=players[1]\n", "   \n", "    player_1_df=df[df['GSISID']==player_1]\n", "    player_1_df=player_1_df.sort_values('Time')\n", "    \n", "    \n", "    index_start1=player_1_df[player_1_df.Event=='ball_snap'].index[0]\n", "    \n", "    index_start1=player_1_df.index.get_loc(index_start1)\n", "                                \n", "    try:\n", "        index_end1=player_1_df[player_1_df.Event=='punt_downed'].index[0]\n", "        index_end1=player_1_df.index.get_loc(index_end1)\n", "    except Exception:\n", "        index_end1=player_1_df[player_1_df.Event=='play_submit'].index[0]\n", "        index_end1=player_1_df.index.get_loc(index_end1)\n", "        \n", "    player_1_df=player_1_df.iloc[index_start1:index_end1+1]\n", "    \n", "    player_2_df=df[df['GSISID']==player_2]\n", "    player_2_df=player_2_df.sort_values('Time')\n", "    \n", "    index_start2=player_2_df[player_2_df.Event=='ball_snap'].index[0]\n", "    \n", "    index_start2=player_2_df.index.get_loc(index_start2)# plays that have ended\n", "                                #play start at ball_snap\n", "                                #play at punt\n", "                                #then end at either punt_downed, play_submit\n", "    try:\n", "        index_end2=player_2_df[player_2_df.Event=='punt_downed'].index[0]\n", "        index_end2=player_2_df.index.get_loc(index_end2)\n", "    except Exception:\n", "        index_end2=player_2_df[player_2_df.Event=='play_submit'].index[0]\n", "        index_end2=player_2_df.index.get_loc(index_end2)\n", "        \n", "    player_2_df=player_2_df.iloc[index_start2:index_end2+1]\n", "    \n", "   \n", "    player_1_injury=player_1_df['Injured'].iloc[0]\n", "    \n", "    fig2 = plt.figure()\n", "    ax2 = fig2.add_subplot(111, aspect='equal')\n", "    ax2.axis('off')\n", "\n", "    ax2.add_patch(\n", "         patches.Rectangle(\n", "            (0, 0),\n", "            120,\n", "            53.3,\n", "            ec='g',\n", "            fill=False,\n", "            alpha=1\n", "         ) ) \n", "\n", "    ax2.add_patch( patches.Rectangle(\n", "            (110, 0),\n", "            10,\n", "            53.3,\n", "            ec='g',\n", "            fill=True,\n", "            facecolor='g',\n", "            alpha=1))\n", "\n", "    ax2.add_patch(\n", "         patches.Rectangle(\n", "            (0, 0),\n", "            10,\n", "            53.3,\n", "            ec='g',\n", "            fill=True,\n", "            facecolor='g',\n", "            alpha=1\n", "         ) ) \n", "\n", "\n", "    for a in range(1,21):\n", "        if a*5!=50:\n", "\n", "            ax2.add_patch(\n", "             patches.Rectangle(\n", "                (10, 0),\n", "                a*5,\n", "                53.3,\n", "                ec='g',\n", "                fill=False,\n", "                alpha=0.3\n", "             ) ) \n", "        else:\n", "            ax2.add_patch(\n", "             patches.Rectangle(\n", "                (10, 0),\n", "                a*5,\n", "                53.3,\n", "                ec='g',\n", "                fill=False,\n", "                alpha=1\n", "             ) ) \n", "\n", "\n", "    plt.xlim((-5,130))\n", "    plt.ylim((-5,58))\n", "\n", "    plt.tick_params(left=False,labelleft=False) \n", "\n", "    plt.title('NGS Player Motion');\n", "    \n", "    plt.scatter(player_1_df['x'],player_1_df['y'],c=making_velocity(player_1_df,player_1),cmap=cm.coolwarm);\n", "    plt.scatter(player_2_df['x'],player_2_df['y'],c=making_velocity(player_2_df,player_2),cmap=cm.coolwarm);\n", "\n", "    if player_1_injury==1:\n", "        plt.text(player_1_df['x'].iloc[0]+3,player_1_df['y'].iloc[0],player_1_df['Role'].iloc[0]+' Injured');\n", "        plt.text(player_2_df['x'].iloc[0]+3,player_2_df['y'].iloc[0]+4,player_2_df['Role'].iloc[0]);\n", "    else:\n", "        plt.text(player_1_df['x'].iloc[0]+3,player_1_df['y'].iloc[0]+4,player_1_df['Role'].iloc[0]);\n", "        plt.text(player_2_df['x'].iloc[0]+3,player_2_df['y'].iloc[0],player_2_df['Role'].iloc[0]+' Injured');\n", "        \n", "    return\n", "        \n", "def ngs_data_transformation(df):\n", "    \n", "    dic={}\n", "    counter=0\n", "    \n", "    df['Play_Identifier']=df['Season_Year'].map(str)+' '+df['GameKey'].map(str)+' '+df['PlayID'].map(str)\n", "    \n", "    for a in df.Play_Identifier.unique():\n", "        \n", "        filtered_df_pre=df[df['Play_Identifier']==a]\n", "        dic[a]=[]\n", "        for b in filtered_df_pre.GSISID.unique():\n", "            filtered_df=df[df['GSISID']==b]\n", "            filtered_df=filtered_df.sort_values('Time')\n", "        \n", "    #Making Velocity Calculations:\n", "            filtered_df['Velocity']=making_velocity(filtered_df,b)\n", "        \n", "    \n", "        \n", "    #Making cumsum distance calculations:\n", "    \n", "            filtered_df['Total_Distance']=filtered_df.dis.cumsum()\n", "        \n", "            dic[a].append(filtered_df.copy())\n", "        \n", "    return dic\n", "\n", "def making_velocity(df,gsisid):  #ensure\n", "\n", "    df=df.sort_values(['Season_Year','GameKey','PlayID','GSISID','Time'])\n", "    \n", "    counter=0\n", "    filtered_df=df[df.GSISID==gsisid]\n", "\n", "    velocity_vals=[0]\n", "    for b in range(1,len(filtered_df)):\n", "        val=filtered_df.iloc[b]\n", "        prev=filtered_df.iloc[b-1]\n", "        velocity=(math.sqrt((val.x-prev.x)**2+(val.y-prev.y)**2))/(val.Time-prev.Time).total_seconds()\n", "        velocity_vals.append(velocity)\n", "                        \n", "    return velocity_vals      \n", "       \n", "def plot_vel_vs_time(df1,df2):\n", "    \n", "    player1=int(df1.GSISID.iloc[0])\n", "    player2=int(df2.GSISID.iloc[1])\n", "    \n", "    player1_injury=df1.Injured.iloc[0]\n", "    \n", "    df1=df1.sort_values('Time')\n", "    df2=df2.sort_values('Time')\n", "    \n", "    index_start1=df1[df1.Event=='ball_snap'].index[0]\n", "    \n", "    index_start1=df1.index.get_loc(index_start1)\n", "    \n", "    try:\n", "        index_end1=df1[df1.Event=='punt_downed'].index[0]\n", "        index_end1=df1.index.get_loc(index_end1)\n", "    except Exception:\n", "        index_end1=df1[df1.Event=='play_submit'].index[0]\n", "        index_end1=df1.index.get_loc(index_end1)\n", "        \n", "    df1=df1.iloc[index_start1:index_end1+1]\n", "    \n", "    index_start2=df2[df2.Event=='ball_snap'].index[0]\n", "    \n", "    index_start2=df2.index.get_loc(index_start2)\n", "    \n", "    try:\n", "        index_end2=df2[df2.Event=='punt_downed'].index[0]\n", "        index_end2=df2.index.get_loc(index_end2)\n", "        \n", "    except Exception:\n", "        index_end2=df2[df2.Event=='play_submit'].index[0]\n", "        index_end2=df2.index.get_loc(index_end2)\n", "        \n", "    df2=df2.iloc[index_start2:index_end2+1]\n", "    \n", "    start_time1=df1.Time.iloc[0]\n", "    start_time2=df2.Time.iloc[0]\n", "    \n", "    \n", "    df1['Time_Elapsed']=(df1['Time']-start_time1).map(lambda x: x.total_seconds())\n", "    df2['Time_Elapsed']=(df2['Time']-start_time2).map(lambda x: x.total_seconds())\n", "    \n", "    \n", "    if player1_injury==0:\n", "        plt.plot(df1['Time_Elapsed'],making_velocity(df1,player1),label='Player '+str(player1),c='g')\n", "        plt.plot(df2['Time_Elapsed'],making_velocity(df2,player2),label='Concussed Player '+str(player2),c='r')\n", "    else:\n", "        plt.plot(df1['Time_Elapsed'],making_velocity(df1,player1),label='Concussed Player '+str(player1),c='r')\n", "        plt.plot(df2['Time_Elapsed'],making_velocity(df2,player2),label='Player '+str(player2),c='g')\n", "        \n", "    plt.title('Velocity vs. Time Elapsed' );\n", "    plt.ylabel('Velocity (yds/sec)')\n", "    plt.xlabel('Time Elapsed (sec)')\n", "    plt.legend()\n", "    \n", "def plot_vel_vs_dist(df1,df2):\n", "    \n", "    player1=int(df1.GSISID.iloc[0])\n", "    player2=int(df2.GSISID.iloc[1])\n", "    \n", "    player1_injury=df1.Injured.iloc[0]\n", "    \n", "    if player1_injury==0:\n", "        plt.plot(df1['Total_Distance'],making_velocity(df1,player1),label='Player '+str(player1),c='g')\n", "        plt.plot(df2['Total_Distance'],making_velocity(df2,player2),label='Concussed Player '+str(player2),c='r')\n", "    else:\n", "        plt.plot(df1['Total_Distance'],making_velocity(df1,player1),label='Concussed Player '+str(player1),c='r')\n", "        plt.plot(df2['Total_Distance'],making_velocity(df2,player2),label='Player '+str(player2),c='g')\n", "        \n", "    plt.title('Velocity vs. Distance Traveled' );\n", "    plt.ylabel('Velocity (yds/s)')\n", "    plt.xlabel('Total Distance Traveled (yds)')\n", "    plt.legend()"]}, {"cell_type": "markdown", "metadata": {"_uuid": "de0dbeb9a1c353d4ebb532e88bea209085b4c735"}, "source": ["# 3 NGS Data Concussion Scenarios\n", "\n", "    * Note: Still Frame Screenshots of hits are in the submitted powerpoint."]}, {"cell_type": "markdown", "metadata": {"_uuid": "a10898ffe5796632667074472cb8d331210f016f"}, "source": ["**Scenario 1**\n", "\n", "* Focus on #13 for the San Fransisco 49ers at the 10 second mark"]}, {"cell_type": "code", "execution_count": 26, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["HTML('<video id=\"vid1\" width=\"800\" height=\"600\" controls> <source src=\"http://a.video.nfl.com//films/vodzilla/153239/Punt_Return_by_Jeremy_Kerley-U64gqush-20181119_154406175_5000k.mp4#t=8,11\" type=\"video/mp4\"></video>')"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Below are stillframes of the concussion inducing block"]}, {"cell_type": "code", "execution_count": 29, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario1_1.png')"]}, {"cell_type": "code", "execution_count": 30, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario1_2.png')"]}, {"cell_type": "code", "execution_count": 31, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario1_3.png')"]}, {"cell_type": "code", "execution_count": 32, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario1_4.png')"]}, {"cell_type": "markdown", "metadata": {"_uuid": "970ff87d405e99a6896e6c2e9ad9d977b430aed8"}, "source": ["\n", "* Concussion occurred when non-injured player (#36 for Bills) ran into injured (#13 for 49ers) player at full speed while the injured player lead with his helmet.\n", "\n", "**Notes:**\n", "\n", "* During impact that occurred, the difference in velocity between the injured and non-injured players was approximately 5 yds/sec. \n", "\n", "\n", "* The punt returned that did occur was on a punt return that lasted approximately 14 seconds because the returner was able to gain decent yardage on the return, which lengthened the play.\n", "\n", "\n", "* The fact that the injured player lead with his head when there was a large difference in velocity at impact, helped prompt the concussion.  If the player did not lead with his helmet, then the chances that a concussion would have occurred would have lessened.\n"]}, {"cell_type": "code", "execution_count": 33, "metadata": {"_uuid": "39fb43ffbf2e75bb5899a6c9d5fd2ba0e7962f8f", "collapsed": true}, "outputs": [], "source": ["output=ngs_data_transformation(ngs_combined)"]}, {"cell_type": "code", "execution_count": 34, "metadata": {"_uuid": "c3152c740d85a7e68ad1549f392cd47a9e7de133", "collapsed": true}, "outputs": [], "source": ["plot_ngs_data(ngs_combined,2016, 144, 2342)"]}, {"cell_type": "code", "execution_count": 35, "metadata": {"_uuid": "64784b2412416c6203f4a323bdeac16f9dde852f", "collapsed": true}, "outputs": [], "source": ["plot_vel_vs_time(output['2016 144 2342'][0],output['2016 144 2342'][1])\n", "plt.axvline(7,c='k');\n", "plt.text(4,2.4,'Concussion \\nOccurrence');\n"]}, {"cell_type": "markdown", "metadata": {"_uuid": "8c1b3dce992c15fb8b5508e667b55bcd750b06be"}, "source": ["**Scenario 2**\n", "\n", "* Focus on the Punt Returner and the incoming tackler at the 11 second mark in the video"]}, {"cell_type": "code", "execution_count": 37, "metadata": {"_uuid": "d6a8818186cbc7217db29370dda341fdb3c0f51c", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["HTML('<video width=\"800\" height=\"600\" controls> <source src=\"http://a.video.nfl.com//films/vodzilla/153233/Kadeem_Carey_punt_return-Vwgfn5k9-20181119_152809972_5000k.mp4#t=9,16\" type=\"video/mp4\"></video>')"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Below are stillframes of the concussion inducing tackle"]}, {"cell_type": "code", "execution_count": 38, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario2_1.png')"]}, {"cell_type": "code", "execution_count": 39, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario2_2.png')"]}, {"cell_type": "code", "execution_count": 40, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario2_3.png')"]}, {"cell_type": "code", "execution_count": null, "metadata": {"hide_input": true, "scrolled": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario2_4.png')"]}, {"cell_type": "markdown", "metadata": {"_uuid": "53a5e646868c7b67d1d37e26ce71d11b65d892ee"}, "source": ["* Concussion occurred when non-injured player (#2 for Broncos) was running at near  full speed and the injured player (#25 for Bears) was running at full speed.\n", "\n", "\n", "* Worth noting that the injured player lead with his helmet, which caused the concussion.\n", "\n", "**Notes**\n", "\n", "* In this scenario, there was a high speed collision between both of the players.  High speed collisions generate more energy and can increase the probability of concussions.\n", "\n", "\n", "* The punt lasted around 12 seconds and the returner was able to return the punt for a decent yardage gain, which allowed the players to build up momentum.\n", "\n", "\n", "* The injured player was able to gain speed to the point where his head first tackle caused a concussion, otherwise a concussion could have been prevented.\n"]}, {"cell_type": "code", "execution_count": 43, "metadata": {"_uuid": "87c41b9976844fec440182426d8f20579e5e0ded", "collapsed": true}, "outputs": [], "source": ["plot_ngs_data(ngs_combined,2016,5,3129)"]}, {"cell_type": "code", "execution_count": 44, "metadata": {"_uuid": "0b91ecbe00b8f93d749cc7cb643ea027bf11dda8", "collapsed": true}, "outputs": [], "source": ["plot_vel_vs_time(output['2016 5 3129'][0],output['2016 5 3129'][1])\n", "plt.axvline(11,c='k');\n", "plt.text(11.3,8,'Concussion \\nOccurrence');"]}, {"cell_type": "markdown", "metadata": {"_uuid": "d70155c0477b116de23dbccd5d1498001df5abe0"}, "source": ["**Scenario 3**\n", "\n", "* Focus on the Panthers Gunner at the top of the screen at the 9 second mark in the video"]}, {"cell_type": "code", "execution_count": 45, "metadata": {"_uuid": "6b8a7b9c540f1f16abfbf27c8a286e60dcf6997b", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["HTML('<video width=\"800\" height=\"600\" controls> <source src=\"http://a.video.nfl.com//films/vodzilla/153234/Punt_by_Kasey_Redfern-w6Cpit4D-20181119_152918853_5000k.mp4#t=8,11\" type=\"video/mp4\"></video>')"]}, {"cell_type": "markdown", "metadata": {}, "source": ["# Below are still frames of the concussion inducing block"]}, {"cell_type": "code", "execution_count": 46, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario3_1.png')"]}, {"cell_type": "code", "execution_count": 47, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario3_2.png')"]}, {"cell_type": "code", "execution_count": 48, "metadata": {"hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/scenario3_3.png')"]}, {"cell_type": "markdown", "metadata": {"_uuid": "65c9a24cc788ecfbca71e2e80b51718687d18d56"}, "source": ["* Concussion occurred when the injured player (#86 for Panthers) was running at near full speed and was blindsided by an oncoming blocker (#28 for Titans) who led with his helmet.\n", "\n", "**Notes**\n", "\n", "* As opposed to the other scenarios, this punt was punted across the 50 yard line, was short and was downed inside the 20 yard line.\n", "\n", "\n", "* However, even though this punt play was only around  6 seconds, the players were able to accelerate quickly and were at near full speed when the concussion occurred 4 seconds into the play. \n", "\n", "\n", "* The non-injured player lead in helmet first into the oncoming tackler, which caused the concussion. \n"]}, {"cell_type": "code", "execution_count": 49, "metadata": {"_uuid": "46f1949f4f2493795aa04a482b5ddd2b1b2d4e8e", "collapsed": true}, "outputs": [], "source": ["plot_ngs_data(ngs_combined,2016,21,2587)"]}, {"cell_type": "code", "execution_count": 50, "metadata": {"_uuid": "435f51f47625ed68c82ebb0f918217909d0d7158", "collapsed": true}, "outputs": [], "source": ["plot_vel_vs_time(output['2016 21 2587'][0],output['2016 21 2587'][1])\n", "plt.axvline(4.3,c='k');\n", "plt.text(2.5,2,'Concussion \\nOccurrence');"]}, {"cell_type": "markdown", "metadata": {"_uuid": "08b3ded8b1f96c57e52c39810daf466c7c3df8c3"}, "source": ["# Proposed Rule Changes\n", "\n", "**A common theme of concussions that occur are twofold:**\n", "\n", "1. Improper Tackling or Blocking Leading with Helmet\n", "    * Some of which are intentional and are unintentional (due to biomechanics)\n", "    * Can cause sudden change in movement of the head, which lead to concussions\n", "\n", "\n", "\n", "2. High Velocity Impact\n", "    * Leads to larger energy transfer, which can increase probability of concussion\n", "\n", "## Dangerous Tackling/Blocking Form\n", "\n", "* The data shows concussions induced from helmet to helmet contact, which are more intentional, are still prevalent on punt plays and make up for 45.9% of all concussions on punts in 2016-2017"]}, {"cell_type": "code", "execution_count": 178, "metadata": {"_uuid": "78ca6770b96c858e38110a30ecdcd5868534a654", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["legend_elements = [Line2D([0], [0], marker='o', color='w', label='2016',\n", "                          markerfacecolor='g', markersize=15),\n", "                   Line2D([0], [0], marker='o', color='w', label='2017',\n", "                          markerfacecolor='r', markersize=15)]\n", "\n", "# Create the figure\n", "fig, ax = plt.subplots()\n", "\n", "fig.set_size_inches(10,6)\n", "ax.legend(handles=legend_elements, loc='upper right')\n", "plt.pie(involved_players[involved_players.Injured==1].groupby(['Season_Year','Primary_Impact_Type']).count()['Injured'],\n", "        labels=['Helmet-to-body','Helmet-to-ground','Helmet-to-helmet','Helmet-to-body','Helmet-to-ground','Helmet-to-helmet','Unclear'],\n", "    explode=[.1,.1,.1,.1,.1,.1,.1],colors=['olivedrab','lightgreen','olivedrab','r','lightsalmon','r','lightsalmon'],startangle=85,\n", "       autopct='%1.1f%%',shadow=True);"]}, {"cell_type": "code", "execution_count": 52, "metadata": {"_uuid": "3175485844968f62e6ce639f1962da36f4ef2a2b", "collapsed": true}, "outputs": [], "source": ["involved_players[involved_players.Injured==1].groupby(['Season_Year','Primary_Impact_Type']).count()['Injured']"]}, {"cell_type": "markdown", "metadata": {"_uuid": "d8506b162ebf3242bef57f6a0d6405adb56dd45b"}, "source": ["### Chi Square Test to test and see effectiveness of new rule change from 2016-2017"]}, {"cell_type": "code", "execution_count": 53, "metadata": {"_uuid": "406baae3f46ef31d07665a514b527ec20f9f0554", "collapsed": true}, "outputs": [], "source": ["involved_players.groupby('Season_Year')['GameKey'].count()"]}, {"cell_type": "code", "execution_count": 54, "metadata": {"_uuid": "d991f52a430584d969bfd3e174c0700ca95c5df1", "collapsed": true}, "outputs": [], "source": ["# chisquare([2016 freq,2017 freq],[expected_freq for 2016, expected_freq for 2017])\n", "chisquare([37,33],[37,37])"]}, {"cell_type": "markdown", "metadata": {"_uuid": "2b87d02bd8476891e8d9f4a868f932db563f0dee"}, "source": ["* The resulting p-value is 0.51.  This means there is a 51% chance that this rule change caused a significant reduction in concussions, which means there is no significant statistical evidence to support that claim.\n", "\n", "\n", "* From the Chi-Square analysis, stricter rule changes need to be made to prevent this dangerous tackling and blocking form.\n", "    * This assumes that the rules added to the 2018 NFL Rule book have not reduced the number of concussions on punt plays.\n", "    \n", "      \n", "    \n", "* A radical new rule for the NFL can incorporate a similar targeting rule employed in college football to help eliminate this dangerous football move to massively reduce number of concussions.\n", "    1. First review can be done to establish intent of the helmet leading tackle or block of which will either confirm or reverse the call.\n", "    2. If a player is charged with two targeting calls, then the player is removed from the game.\n"]}, {"cell_type": "markdown", "metadata": {"_uuid": "0156840cc9b8c7fa69b9082407c88aee17b639bb"}, "source": ["# Similar NBA Ejection Structure to Proposed Solution"]}, {"cell_type": "markdown", "metadata": {"_uuid": "f800cc268db4c313f383b84a24ffb4428db76c3c"}, "source": ["* A similar ejection rule structure is emphasized in the NBA, where if one player gets two technical fouls, then they are ejected from the game."]}, {"cell_type": "markdown", "metadata": {}, "source": ["Reading in the technical foul and ejection data from all NBA players during the 2017-2018 NBA season"]}, {"cell_type": "code", "execution_count": 151, "metadata": {"_uuid": "006d426003ec4f40fc0768b903c47a329d0b60e4", "collapsed": true}, "outputs": [], "source": ["nba_techs=pd.read_csv('../input/user-input-data/nba_stats.txt',sep='\\t')"]}, {"cell_type": "code", "execution_count": 152, "metadata": {"collapsed": true}, "outputs": [], "source": ["nba_techs.shape"]}, {"cell_type": "code", "execution_count": 165, "metadata": {"collapsed": true}, "outputs": [], "source": ["def tech_feat(x):\n", "    if x>1:\n", "        return 1\n", "    else:\n", "        return 0"]}, {"cell_type": "code", "execution_count": 167, "metadata": {"collapsed": true}, "outputs": [], "source": ["nba_techs=nba_techs[nba_techs['TECH']!=0]\n", "nba_techs['EJECT_binary']=nba_techs.EJECT.map(tech_feat)"]}, {"cell_type": "code", "execution_count": 171, "metadata": {"collapsed": true}, "outputs": [], "source": ["nba_techs.groupby(['EJECT_binary']).count()['MISC']"]}, {"cell_type": "code", "execution_count": 209, "metadata": {"collapsed": true, "hide_input": true}, "outputs": [], "source": ["fig, ax = plt.subplots()\n", "fig.set_size_inches(10,5)\n", "plt.pie(nba_techs.groupby(['EJECT_binary']).count()['MISC'],explode=[0.3,0.3],shadow=True,labels=['Not Ejected','Ejected'],autopct='%1.1f%%',colors=['g','r']);\n", "plt.title('Percentage of Players Ejected with at Least One Technical Foul');"]}, {"cell_type": "markdown", "metadata": {}, "source": ["* The above data shows that among players who have committed at least one technical foul, a significant majority of the players do not get ejected at all.  Therefore, the rules that are in place incentivize the players to not get 2 technical fouls within games to avoid being ejected."]}, {"cell_type": "markdown", "metadata": {"_uuid": "a553ba1b7e75722f13f4f114a4d3134a6c15f9a4"}, "source": ["## Dealing with High Velocity Impact"]}, {"cell_type": "markdown", "metadata": {"_uuid": "14ed150f3190b53d860cfd782692d443880f55b7"}, "source": ["* Since there is no data showing the point in time when a player was hit, the data was filtered out to only include players who got a concussion as a result of a tackle.\n", "    * The velocity that is displayed below is the velocity of players when \n", "        * A punt was received or\n", "        * A punt was downed or\n", "        * A punt was kicked out of bounds\n"]}, {"cell_type": "code", "execution_count": 65, "metadata": {"_uuid": "cead81e8ff097444161c2910c016100d3a7f0506", "collapsed": true}, "outputs": [], "source": ["ngs_combined1=ngs_combined[(ngs_combined.Event=='punt_received')|(ngs_combined.Event=='out_of_bounds')|(ngs_combined.Event=='punt_downed')]\n", "ngs_combined1['Velocity']=ngs_combined1['dis']/0.1\n", "ngs_combined1.groupby('Primary_Impact_Type')['Velocity'].mean()\n", "\n", "ngs1_merge_non_injury=pd.merge(ngs1,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'],how='outer')\n", "ngs1_merge_non_injury_filt=ngs1_merge_non_injury[ngs1_merge_non_injury.Injured.isnull()]\n", "ngs1_merge_non_injury_filt=ngs1_merge_non_injury_filt[(ngs1_merge_non_injury_filt.Event=='punt_received')|(ngs1_merge_non_injury_filt.Event=='out_of_bounds')|(ngs1_merge_non_injury_filt.Event=='punt_downed')]\n", "ngs1_merge_non_injury_filt['Velocity']=ngs1_merge_non_injury_filt['dis']/0.1\n", "vel_li_non_injury=ngs1_merge_non_injury_filt['Velocity'].values\n", "\n", "ngs2_merge_non_injury=pd.merge(ngs2,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'],how='outer')\n", "ngs2_merge_non_injury_filt=ngs2_merge_non_injury[ngs2_merge_non_injury.Injured.isnull()]\n", "ngs2_merge_non_injury_filt=ngs2_merge_non_injury_filt[(ngs2_merge_non_injury_filt.Event=='punt_received')|(ngs2_merge_non_injury_filt.Event=='out_of_bounds')|(ngs2_merge_non_injury_filt.Event=='punt_downed')]\n", "ngs2_merge_non_injury_filt['Velocity']=ngs2_merge_non_injury_filt['dis']/0.1\n", "np.append(vel_li_non_injury,ngs2_merge_non_injury_filt['Velocity'].values)\n", "\n", "ngs3_merge_non_injury=pd.merge(ngs3,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'],how='outer')\n", "ngs3_merge_non_injury_filt=ngs3_merge_non_injury[ngs3_merge_non_injury.Injured.isnull()]\n", "ngs3_merge_non_injury_filt=ngs3_merge_non_injury_filt[(ngs3_merge_non_injury_filt.Event=='punt_received')|(ngs3_merge_non_injury_filt.Event=='out_of_bounds')|(ngs3_merge_non_injury_filt.Event=='punt_downed')]\n", "ngs3_merge_non_injury_filt['Velocity']=ngs3_merge_non_injury_filt['dis']/0.1\n", "np.append(vel_li_non_injury,ngs3_merge_non_injury_filt['Velocity'].values)\n", "\n", "ngs4_merge_non_injury=pd.merge(ngs4,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'],how='outer')\n", "ngs4_merge_non_injury_filt=ngs4_merge_non_injury[ngs4_merge_non_injury.Injured.isnull()]\n", "ngs4_merge_non_injury_filt=ngs4_merge_non_injury_filt[(ngs4_merge_non_injury_filt.Event=='punt_received')|(ngs4_merge_non_injury_filt.Event=='out_of_bounds')|(ngs4_merge_non_injury_filt.Event=='punt_downed')]\n", "ngs4_merge_non_injury_filt['Velocity']=ngs4_merge_non_injury_filt['dis']/0.1\n", "np.append(vel_li_non_injury,ngs4_merge_non_injury_filt['Velocity'].values)\n", "\n", "ngs5_merge_non_injury=pd.merge(ngs5,involved_players,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'],how='outer')\n", "ngs5_merge_non_injury_filt=ngs5_merge_non_injury[ngs5_merge_non_injury.Injured.isnull()]\n", "ngs5_merge_non_injury_filt=ngs5_merge_non_injury_filt[(ngs5_merge_non_injury_filt.Event=='punt_received')|(ngs5_merge_non_injury_filt.Event=='out_of_bounds')|(ngs5_merge_non_injury_filt.Event=='punt_downed')]\n", "ngs5_merge_non_injury_filt['Velocity']=ngs5_merge_non_injury_filt['dis']/0.1\n", "np.append(vel_li_non_injury,ngs5_merge_non_injury_filt['Velocity'].values)\n", "\n", "vel_li_non_injury\n"]}, {"cell_type": "markdown", "metadata": {"_uuid": "0f2d94c520e5e9fbee6d8b95df9f27a90fd993d4"}, "source": ["* Since there is no data showing the point in time when a player was hit, the data was filtered out to only include players who got a concussion as a result of a tackle.\n", "\n", "\n", "* The velocity that is displayed below is the velocity of players when \n", "    * A punt was received or\n", "    * A punt was downed or\n", "    * A punt was kicked out of bounds\n"]}, {"cell_type": "code", "execution_count": 66, "metadata": {"_uuid": "8c795db0da240f6376abbd7f6db5d1be9b9d6e84", "collapsed": true}, "outputs": [], "source": ["ngs_combined1.groupby('Primary_Impact_Type')['Velocity'].mean()"]}, {"cell_type": "markdown", "metadata": {"_uuid": "073425453c68e618f49d705448ee4f734d73d0b7"}, "source": ["* The average player velocity on a developed punt play is high on plays with concussions as seen above.\n", "\n", "\n", "* The boxplot below shows the average player velocity on a developed punt play on plays with no concussions:"]}, {"cell_type": "code", "execution_count": 67, "metadata": {"_uuid": "5056ef2b9792c47b17789dd8b4e034bbe426497f", "collapsed": true}, "outputs": [], "source": ["sns.boxplot(vel_li_non_injury);\n", "plt.title('Average Player Velocity on Devoloped Punt Plays');\n", "plt.xlabel('Velocity (yds/sec)');"]}, {"cell_type": "code", "execution_count": 68, "metadata": {"_uuid": "8fff895061d86426503a5eabfb8ac5c7818014a7", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["print('The average player velocity on a developed punt play on plays with no concussions is '+str(round(vel_li_non_injury.mean(),2))+ ' yds/sec')\n", "print()\n", "print('The average player velocity standard deviation on a developed punt play on plays with no concussions are '+str(round(vel_li_non_injury.std(),2))+ ' yds/sec')"]}, {"cell_type": "code", "execution_count": 69, "metadata": {"_kg_hide-input": true, "_kg_hide-output": true, "_uuid": "4b053fa519528c456fb3fc4e86b152791f4ab6ad", "collapsed": true}, "outputs": [], "source": ["los_pos=['PRT','PRG','PLS','PLG','PLT','PRW','PLW','PDR1','PDR2','PDR3','PDL3','PDL2','PDL1','PLR','PLM','PLL']"]}, {"cell_type": "markdown", "metadata": {"_uuid": "57175d9e25d6f1c27c8c1b2f7ffbecf84b7c6caa"}, "source": ["* For the players of focus in a punt formation near the line of scrimmage near the long snapper, their average velocities are in general faster during punt plays that have concussions."]}, {"cell_type": "code", "execution_count": 70, "metadata": {"_uuid": "ce84aa93bac3efc7fba2bfeb6a1007b51404723e", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["sns.kdeplot(vel_li_non_injury,bw=0.31,shade=True,label='Non-Injury Punt Plays')\n", "sns.kdeplot(ngs_combined1[ngs_combined1.Role.isin(los_pos)].Velocity,bw=0.3,color='r',label='Injury Punt Plays',shade=True)\n", "plt.xlim(0,10);\n", "plt.title('Player Velocity during Punt Plays');\n", "plt.xlabel('Velocity (yd/sec)');"]}, {"cell_type": "markdown", "metadata": {"_uuid": "b18f5b8b146a365e7452b4f7d7e3a485a2bf18b9"}, "source": ["* For the velocities that are slower than 5 yds/sec, the main primary impact type were all helmet to helmet hits."]}, {"cell_type": "code", "execution_count": 71, "metadata": {"_uuid": "bcebfcf20156b9c60d0bd997f77a30b7e2b24993", "collapsed": true}, "outputs": [], "source": ["ngs_combined1[(ngs_combined1.Role.isin(los_pos))&(ngs_combined1.Velocity<5)].groupby('Primary_Impact_Type').count()['PlayID']"]}, {"cell_type": "markdown", "metadata": {"_uuid": "185425f7448f0cd4d171bc4faf08da1adb83070a"}, "source": ["* The data shows that for hits that occur at faster speeds, concussions are more likely.  However, for concussions that occur at slower speeds, helmet to helmet contact is the only causing factor.\n", "\n", "\n", "* With this said, even though the velocity statistics are not statistically different between punt plays with concussions versus those without, the punt play formation still needs to be changed to fundamentally help reduce the average player speed as much as possible to reduce concussion provoking plays.\n", "\n", "\n", "* To maintain the integrity of the game so that the resulting punt play is similar to the original, only the formation alignment will be changed to reduce the average player\u00e2\u20ac\u2122s velocity on punt plays to help reduce concussions.\n"]}, {"cell_type": "markdown", "metadata": {"_uuid": "99c80ab1ba9538ad5b03c12f690d42116f87c780"}, "source": ["# Proposed Rule Changes: \n", "  **Changing the Punt Formation**  "]}, {"cell_type": "markdown", "metadata": {"_uuid": "b9860bdf51b71a1922d0ae15651ccd579146dc4f"}, "source": ["* An area of interest is to identify the players who are most frequently involved in concussion inducing punt plays.\n", "\n", "\n", "* Concussion Player Involvement is identified as being a player who either experiences a concussion or whose contact triggers a concussion of another player.\n", "\n", "\n", "* Is important to understand which positions of a punt formation are more likely to have concussion player involvement and identify why those positions are more likely to induce concussions.\n"]}, {"cell_type": "markdown", "metadata": {"_uuid": "f530565fdaa0338648cabb9a6f403e0d649e479e"}, "source": ["# Proposed Rule Changes:\n", "   * Changing the Punt Formation:\n", "        * Concussion Player Involvement for Punt Coverage Formations"]}, {"cell_type": "markdown", "metadata": {"_uuid": "d6135cb144b0d78b7c50a0079da809e662b901e8"}, "source": ["### Making DataFrame that Shows Involved Players in Concussion Play"]}, {"cell_type": "code", "execution_count": 72, "metadata": {"_uuid": "c0a8819a52f75d80568dfd9678c75de867f7ade2", "collapsed": true}, "outputs": [], "source": ["df=pd.read_csv('../input/NFL-Punt-Analytics-Competition/video_review.csv')\n", "role=pd.read_csv('../input/NFL-Punt-Analytics-Competition/play_player_role_data.csv')\n", "\n", "injured_player=pd.merge(df,role,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])"]}, {"cell_type": "code", "execution_count": 73, "metadata": {"_uuid": "e7426c4978ea8e9eb026e8f52d76f0bc910afdc5", "collapsed": true}, "outputs": [], "source": ["df.Primary_Partner_GSISID=df.Primary_Partner_GSISID.replace([np.nan,'Unclear'],0)\n", "df.Primary_Partner_GSISID=df.Primary_Partner_GSISID.map(int)"]}, {"cell_type": "code", "execution_count": 74, "metadata": {"_uuid": "ad0719c6d4f58c7d4c76749313573939658c8dd9", "collapsed": true}, "outputs": [], "source": ["involved_player=pd.merge(role,df,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','Primary_Partner_GSISID'])\n", "involved_player1=involved_player.rename(columns={'GSISID_x':'Involved_Player_GSISID','GSISID_y':'Injured_Player_GSISID'})\n", "\n", "injured_player2=injured_player[['Season_Year', 'GameKey', 'PlayID', 'GSISID','Role', 'Player_Activity_Derived',\n", "        'Primary_Impact_Type']]\n", "involved_player2=involved_player1[['Season_Year', 'GameKey', 'PlayID', 'Involved_Player_GSISID', 'Role','Player_Activity_Derived',\n", "                                   'Primary_Impact_Type']]\n", "\n", "involved_player2=involved_player2.rename(columns={'Involved_Player_GSISID':'GSISID'})\n", "\n", "involved_player2['Index']=np.arange(37,len(involved_player2)+37)\n", "involved_player2.set_index('Index',inplace=True)\n", "\n", "involved_player2['Injured']=0\n", "injured_player2['Injured']=1\n", "\n", "concussion_inv=pd.concat([injured_player2,involved_player2])"]}, {"cell_type": "markdown", "metadata": {"_uuid": "6fb6c8a4404901872b543f0e503ee972016eb5e2"}, "source": ["* Below are the First 5 Rows of the DataFrame that shows the involved players of a concussion play along with their punt role.  The 'Injured' column allows the capability to easily filter the uninjured players from the injured ones."]}, {"cell_type": "code", "execution_count": 75, "metadata": {"_uuid": "171ae9531a4b5772059ab930e9e12314028f6611", "collapsed": true}, "outputs": [], "source": ["concussion_inv.head()"]}, {"cell_type": "markdown", "metadata": {"_uuid": "0a31869298b01dfbead8b981866bfd49f9762e81"}, "source": ["### Making graphic that shows the positions that are most frequently involved in concussions on punt plays."]}, {"cell_type": "code", "execution_count": 76, "metadata": {"_uuid": "d4b98380a9512fc2e6f21e28e4d6f9bce7acd595", "collapsed": true}, "outputs": [], "source": ["role_injured=injured_player2.groupby('Role').count()[['GameKey']]\n", "role_part=involved_player2.groupby('Role').count()[['GameKey']]\n", "\n", "positions_li_cov=['GR','PRT','PRG','PLS','PLG','PLT','GL','PRW','PLW','PC','PPR','P']\n", "positions_li_ret=['VRo','VRi','PDR1','PDR2','PDR3','PDL3','PDL2','PDL1','VL',\n", "             'PLR','PLM','PLL','PFB','PR']\n", "\n", "los_pos=['PRT','PRG','PLS','PLG','PLT','PRW','PLW','PDR1','PDR2','PDR3','PDL3','PDL2','PDL1','PLR','PLM','PLL']\n", "\n", "df_pos=pd.DataFrame(role_part,index=(positions_li_ret+positions_li_cov),columns=['Count'])\n", "df_pos=df_pos.replace(np.nan,0)\n", "\n", "df_role_injured=pd.DataFrame(pd.merge(df_pos,role_injured,left_index=True,right_index=True,how='outer').sum(axis=1),columns=['Count'])\n", "\n", "role_part=role_part.rename(index={'PLL1':'PLL','VLo':'VL'})\n", "\n", "df_role_part=pd.DataFrame(pd.merge(df_pos,role_part,left_index=True,right_index=True,how='outer').sum(axis=1),columns=['Count'])\n", "\n", "df_role_injured.at['VRi']=1\n", "\n", "df_role_injured.drop('VR',inplace=True)\n", "\n", "df_pos_ovr=df_role_injured+df_role_part\n", "\n", "df_pos_ovr['Return']=[0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,1,1]\n", "\n", "df_pos_ovr=df_pos_ovr.reindex((positions_li_cov+positions_li_ret))"]}, {"cell_type": "markdown", "metadata": {"_uuid": "9ba2bbd7292f14dc39d70b045b58df0832f5a2a2"}, "source": ["* Count Information of All the Punt Coverage and Return Formation Positions as specified by the Data Manual"]}, {"cell_type": "code", "execution_count": 77, "metadata": {"_uuid": "ad8425078af05cc20ce368751d153efadac1fbf7", "collapsed": true}, "outputs": [], "source": ["df_pos_ovr"]}, {"cell_type": "markdown", "metadata": {"_uuid": "276eb1bf2092093daaa560c7bfed40f24058a145"}, "source": ["* Graphic Showing the Positions that are most involved in the **Punt Coverage Formation** with the counts specified by <span style='color:blue'>blue</span>  to<span style='color:red'> red </span>color mapping:"]}, {"cell_type": "markdown", "metadata": {"_uuid": "98730fef2cb95ec2c0fc0374967984abd2952831"}, "source": ["<span style='color:blue'>\n", "Low Involvement  </span> to\n", "<span style='color:red'>    \n", "High Involvement </span>"]}, {"cell_type": "code", "execution_count": 78, "metadata": {"_uuid": "26906fa8e08271ca803dadbbf36923874a4a0470", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["#Punt Coverage\n", "fig = plt.figure()\n", "ax = fig.add_subplot(111)\n", "ax.axis('off')\n", "ovr=df_pos_ovr[df_pos_ovr.Return==0]\n", "\n", "x=[0,0.1,0.05,0,0.05,0.1,0,0.3,0.3,0.7,1.4,3]\n", "y=[10,6,5,4,3,2,-2,6.5,1.5,4,5,4]\n", "plt.scatter(x,y,c=df_pos_ovr[df_pos_ovr.Return==0]['Count'],cmap=cm.coolwarm)\n", "\n", "plt.tick_params(       \n", "    bottom=False,      \n", "    top=False,        \n", "    labelbottom=False,\n", "    left=False,\n", "    labelleft=False) \n", "\n", "counter=0\n", "for i,j in zip(x,y):\n", "    if i<0.7:\n", "        ax.annotate(ovr.index[counter], xy=(i,j), xytext=(-35,5), textcoords='offset points')\n", "    if i>=0.7:\n", "        ax.annotate(ovr.index[counter], xy=(i,j), xytext=(15,0), textcoords='offset points')\n", "    counter+=1\n", "plt.title('Punt Coverage Concussion Involvement');"]}, {"cell_type": "markdown", "metadata": {"_uuid": "d866702e9149f5ad7a3c4022aee38efad71df67d"}, "source": ["* As indicated from the Data, it can be seen majority of the players who are involved in concussion plays are at or near the line of scrimmage, which is 92.9%."]}, {"cell_type": "code", "execution_count": 79, "metadata": {"_uuid": "ab7119f29e3a548e1b496269648d2c0285392aa4", "collapsed": true}, "outputs": [], "source": ["cov_form_count=df_pos_ovr[((df_pos_ovr.index.isin(los_pos+['GR','GL'])))&(df_pos_ovr.Return==0)].sum()['Count']\n", "los_percent_cov=cov_form_count/df_pos_ovr[df_pos_ovr.Return==0].sum()['Count']\n", "round(los_percent_cov,3)"]}, {"cell_type": "markdown", "metadata": {"_uuid": "0a95ea9a30ccd51f9317be05cd713e304cf5784a"}, "source": ["* However, after calculating the gunners\u00e2\u20ac\u2122 concussion involvement proportion from the players at or near the line of scrimmage, the percentage accounted for only 21.4% of those players involved in concussion inducing punt plays."]}, {"cell_type": "code", "execution_count": 80, "metadata": {"_uuid": "9661f0cbae0595f2152dc603cf7773b868697411", "collapsed": true}, "outputs": [], "source": ["cov_form_count_only_los=df_pos_ovr[((df_pos_ovr.index.isin(los_pos)))&(df_pos_ovr.Return==0)].sum()['Count']\n", "los_percent_cov_byball=los_percent_cov-cov_form_count_only_los/df_pos_ovr[df_pos_ovr.Return==0].sum()['Count']\n", "round(los_percent_cov_byball,3)"]}, {"cell_type": "markdown", "metadata": {"_uuid": "8f4f04b3c6a03a693b195b75c81ce54454eaed05"}, "source": ["* This indicates, that approximately 71.4% of players who are involved concussion inducing plays are at or near the line of scrimmage near the football snap location."]}, {"cell_type": "code", "execution_count": 81, "metadata": {"_uuid": "a230d584f248bc221bcbad9eb8540e80f46ee9eb", "collapsed": true}, "outputs": [], "source": ["round(los_percent_cov-los_percent_cov_byball,3)"]}, {"cell_type": "markdown", "metadata": {"_uuid": "2683fe63a80ede739c4feea827e2adc357561024"}, "source": ["* Graphic Showing the Positions that are most involved in the **Punt Return Formation** with the counts specified by <span style='color:blue'>blue</span>  to<span style='color:red'> red </span>color mapping:"]}, {"cell_type": "markdown", "metadata": {"_uuid": "d826c61d89c85e70b59269bd73eecce96a60196f"}, "source": ["<span style='color:blue'>\n", "Low Involvement  </span>to\n", "<span style='color:red'>    \n", "High Involvement </span>"]}, {"cell_type": "code", "execution_count": 82, "metadata": {"_uuid": "6ad8aa28dcfe46c60d1af05c589b229b0a604b45", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["#Punt Return\n", "fig = plt.figure()\n", "ax = fig.add_subplot(111)\n", "ovr=df_pos_ovr[df_pos_ovr.Return==1]\n", "\n", "ax.axis('off')\n", "\n", "x=[0,0,0,0,0,0,0,0,0,1,1,1,6,8]\n", "y=[10,9,6,5,4,3,2,1,-2,5.5,4.5,3.5,4.5,4.5]\n", "plt.scatter(x,y,c=ovr['Count'],cmap=cm.coolwarm)\n", "\n", "\n", "plt.tick_params(       \n", "    bottom=False,      \n", "    top=False,        \n", "    labelbottom=False,\n", "    left=False,\n", "    labelleft=False) \n", "\n", "counter=0\n", "for i,j in zip(x,y):\n", "    if i==0:\n", "\n", "        ax.annotate(ovr.index[counter], xy=(i,j), xytext=(-35,5), textcoords='offset points')\n", "    else:\n", "\n", "        ax.annotate(ovr.index[counter], xy=(i,j), xytext=(15,5), textcoords='offset points')\n", "    \n", "    counter+=1\n", "plt.title('Punt Return Concussion Involvement');"]}, {"cell_type": "markdown", "metadata": {"_uuid": "6e62d473512cfa73c150390dfe300f4a92b3e7d4"}, "source": ["* As indicated from the data, it can be seen that the most frequent position of concussion involvement is the PR position, the position that fields the punts.  \n", "\n", "* The proportion for that position alone accounts for approximately 46.4% of all concussion involved players that are in the return formation.\n", "\n", "* It makes sense that the most frequent position of involvement in concussion inducing plays is the PR position because that is the main focus of protection/attack once the PR fields the ball."]}, {"cell_type": "code", "execution_count": 83, "metadata": {"_uuid": "e98720b6a8f8b37234245dfd6bf462ad29e3114d", "collapsed": true}, "outputs": [], "source": ["return_form_count=df_pos_ovr[(df_pos_ovr.index.isin(['PR']))&(df_pos_ovr.Return==1)].sum()['Count']\n", "round(return_form_count/df_pos_ovr[df_pos_ovr.Return==1].sum()['Count'],3)"]}, {"cell_type": "markdown", "metadata": {"_uuid": "b857a20c6ab58dd2075b861a1a93c577e042365f"}, "source": ["* The proportion of players involved in concussion inducing plays that are at or near the line of scrimmage and take on blockers only account for nearly 43% of the involved players that are in the return formation and is circled above."]}, {"cell_type": "code", "execution_count": 84, "metadata": {"_uuid": "e731d3bd0f36dd23d60d977bf0dff664ee33d41c", "collapsed": true}, "outputs": [], "source": ["return_form_count=df_pos_ovr[(df_pos_ovr.index.isin(los_pos))&(df_pos_ovr.Return==1)].sum()['Count']\n", "round(return_form_count/df_pos_ovr[df_pos_ovr.Return==1].sum()['Count'],3)"]}, {"cell_type": "markdown", "metadata": {"_uuid": "3a33ce7812783c27d19c3317ca6b730b08281835"}, "source": ["## Overall Concussion Involvement"]}, {"cell_type": "markdown", "metadata": {"_uuid": "24f23d0b1b238674079e600db58135fac4954ad3"}, "source": ["* Including the PR position, players at or near the line of scrimmage in the trenches account for 60% of all players involved in concussion inducing events."]}, {"cell_type": "code", "execution_count": 85, "metadata": {"_uuid": "a9d6429620802447ca7b164943afa1a0d2abff1e", "collapsed": true}, "outputs": [], "source": ["df_pos_ovr[df_pos_ovr.index.isin(los_pos)].sum()['Count']/df_pos_ovr['Count'].sum()"]}, {"cell_type": "markdown", "metadata": {"_uuid": "f12837a77d8a6411fc0af9073e18e28f063e7ea1"}, "source": ["* Without accounting for the PR position, players at or near the line of scrimmage in the trenches account for 73.7% of all players involved in concussion inducing events.\n", "\n", "* Due to such a high proportion of involvement, any changes that need to be made, need to be focused on these players at or near the line of scrimmage by the ball snap location, of which are circled below:"]}, {"cell_type": "code", "execution_count": 86, "metadata": {"_uuid": "b684bf1a83c8a4766cea7664b28febfa7d8276da", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["print(df_pos_ovr.iloc[-1].name)\n", "round(df_pos_ovr[df_pos_ovr.index.isin(los_pos)].sum()['Count']/df_pos_ovr['Count'].iloc[:-1].sum(),3)"]}, {"cell_type": "code", "execution_count": 9, "metadata": {"hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/punt_coverage_formation_circle.png')"]}, {"cell_type": "code", "execution_count": 8, "metadata": {"hide_input": true}, "outputs": [], "source": ["Image('../input/user-input-data/punt_return_formation_circled.png')"]}, {"cell_type": "markdown", "metadata": {"_uuid": "23a33082952faaa52519d76370e2bbc22c2e541c"}, "source": ["# Proposed Rule Changes\n", "   * Changing the Punt Formation:\n", "        * Cause of Concussion Involvement"]}, {"cell_type": "markdown", "metadata": {"_uuid": "9f84283169848ff8f7c18a25ba143fb0fec5d378"}, "source": ["* Comparing the velocity of the players that are at or near the line of scrimmage by the snap location (or punt non-gunners) to the gunner players, it is seen that their velocities are in general faster at the time when punt plays are fair caught or are fielded."]}, {"cell_type": "markdown", "metadata": {"_uuid": "49d88196cc1422d9bf1c4700b53729ef70912776"}, "source": ["### Making the appropriate datasets for this analysis."]}, {"cell_type": "code", "execution_count": 87, "metadata": {"_uuid": "83543e01702e0bccf4587790b41e80cfbe3919ad", "collapsed": true}, "outputs": [], "source": ["ngs1_fair_catch=ngs1[ngs1.Event=='fair_catch']\n", "ngs2_fair_catch=ngs2[ngs2.Event=='fair_catch']\n", "ngs3_fair_catch=ngs3[ngs3.Event=='fair_catch']\n", "ngs4_fair_catch=ngs4[ngs4.Event=='fair_catch']\n", "ngs5_fair_catch=ngs5[ngs5.Event=='fair_catch']"]}, {"cell_type": "code", "execution_count": 88, "metadata": {"_uuid": "57f2ec235a12f4ea32ec72d8da00a66f7356528a", "collapsed": true}, "outputs": [], "source": ["injured_player['Injured']=1\n", "injured_player=injured_player[['Season_Year','GameKey','PlayID','Injured']]"]}, {"cell_type": "code", "execution_count": 89, "metadata": {"_uuid": "305da468487026ad4461c27941dfe6a1b1c9115f", "collapsed": true}, "outputs": [], "source": ["fin_fair_catch=pd.concat([ngs1_fair_catch,ngs2_fair_catch,ngs3_fair_catch,ngs4_fair_catch,ngs5_fair_catch])"]}, {"cell_type": "code", "execution_count": 90, "metadata": {"_uuid": "d4f84f50fc004955aa647c5ac4c839439b9d6510", "collapsed": true}, "outputs": [], "source": ["merged_fair_catch=pd.merge(role,fin_fair_catch,left_on=['Season_Year','GameKey','PlayID','GSISID'],right_on=['Season_Year','GameKey','PlayID','GSISID'])\n", "merged_fair_catch=pd.merge(merged_fair_catch,injured_player,left_on=['Season_Year','GameKey','PlayID'],right_on=['Season_Year','GameKey','PlayID'],how='left')\n", "merged_fair_catch['Injured']=merged_fair_catch['Injured'].fillna(0)\n", "merged_fair_catch['Velocity']=merged_fair_catch['dis']/0.1"]}, {"cell_type": "code", "execution_count": 91, "metadata": {"_uuid": "f9b4466e93671006e3454563a265ba3b67bd1918", "collapsed": true}, "outputs": [], "source": ["gunner=['VRo','VRi','VL','GR','GL']\n", "los_pos=['PRT','PRG','PLS','PLG','PLT','PRW','PLW','PDR1','PDR2','PDR3','PDL3','PDL2','PDL1','PLR','PLM','PLL']"]}, {"cell_type": "code", "execution_count": 92, "metadata": {"_uuid": "052a3df2793e343d82f319ad0fb453f62dd9321e", "collapsed": true}, "outputs": [], "source": ["merged_fair_catch_non_gunner=merged_fair_catch[merged_fair_catch.Role.isin(los_pos)][['Velocity']]\n", "merged_fair_catch_gunner=merged_fair_catch[merged_fair_catch.Role.isin(gunner)][['Velocity']]"]}, {"cell_type": "markdown", "metadata": {"_uuid": "b6f823b6874206867c223bd3aa967e8add113c62"}, "source": ["* Comparing the velocity of the players that are at or near the line of scrimmage by the snap location (or punt non-gunners) to the gunner players, it is seen that their velocities are in general faster at the time when punt plays are fair caught.\n", "\n", "* A reason for this is because the gunners get to the punt returner rather quickly so that they in most cases have to slow down, whereas the other players are playing \u00e2\u20ac\u02dccatch up\u00e2\u20ac\u2122 to the gunners and therefore they are on average faster during those times."]}, {"cell_type": "code", "execution_count": 93, "metadata": {"_uuid": "b93df23f7d1d8d62fae9094e75b8ad7fbecf1daa", "collapsed": true}, "outputs": [], "source": ["sns.boxplot(merged_fair_catch_gunner.Velocity);\n", "plt.title('Velocity of Punt Gunners during Fair Caught Punts');"]}, {"cell_type": "code", "execution_count": 94, "metadata": {"_uuid": "b6f2dd6e65afc38d3d8fb2667717be3ef47e0a60", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["print('Punt Gunners average velocity at time of when a punt if fair caught or is fielded: '+str(round(merged_fair_catch_gunner.Velocity.mean(),2))+' yds/sec.')"]}, {"cell_type": "code", "execution_count": 95, "metadata": {"_uuid": "6cdfdcc95349ab3ac6b8a22798a032aab7c14924", "collapsed": true}, "outputs": [], "source": ["sns.boxplot(merged_fair_catch_non_gunner.Velocity,color='r');\n", "plt.title('Velocity of Punt Non-Gunners during Fair Caught Punts');"]}, {"cell_type": "code", "execution_count": 96, "metadata": {"_uuid": "fba6cd28d5f7f689da9eabc8cea90d6eff095e0b", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["print('Punt Gunners average velocity at time of when a punt if fair caught or is fielded: '+str(round(merged_fair_catch_non_gunner.Velocity.mean(),2))+' yds/sec.')"]}, {"cell_type": "markdown", "metadata": {"_uuid": "79a6d94730e1df19fd0de55d00a7720644676a15"}, "source": ["### Checking if there is a statisically proven difference between the velocities of players who are punt gunners versus punt non-gunners."]}, {"cell_type": "code", "execution_count": 97, "metadata": {"_uuid": "7a0d43a310d64d3f5a159616b05520c5f9deb539", "collapsed": true}, "outputs": [], "source": ["ttest_ind(merged_fair_catch_non_gunner,merged_fair_catch_gunner,equal_var=False)"]}, {"cell_type": "markdown", "metadata": {"_uuid": "2ae8c50babc3c4bbec0ea032619ee9d2f5d230f6"}, "source": ["* Statistically proving that both of these samples of velocities between the punt gunners and the punt non-gunners, a 2 sample independent t-test was used\n", "\n", "\n", "* The test gave a p-value of 2.47e-81.  That means that both of these samples statistically have a different velocity population.\n", "\n", "\n", "* Therefore, the gunner position is statistically slower at the time when a punt is fair caught or fielded than the non-gunner positions that are at or near the line of scrimmage by the ball snap location.\n"]}, {"cell_type": "markdown", "metadata": {"_uuid": "dc489344a8e1e8e63cdeb2eaea2384d4d1052260"}, "source": ["# Proposed Rule Changes\n", "## Changing the Punt Formation: \n", "### Proposed Solution"]}, {"cell_type": "markdown", "metadata": {"_uuid": "6e518230438d1114f179948a70384dc4fed5e5c4"}, "source": ["* It would comprise of reducing the allowed number of players at or near the line of scrimmage by the ball snap location for both the return team and the coverage team.\n", "\n", "\n", "* Currently there are at least 10 players at or near the line of scrimmage by the ball snap location.\n", "\n", "\n", "* By allowing only 8 players in this area, this will reduce the number of players who are running full speed down the field.\n"]}, {"cell_type": "code", "execution_count": 98, "metadata": {"_uuid": "0bc5222eb6129a7ae791ac75d6473b089f1eb2d3", "collapsed": true, "hide_input": true}, "outputs": [], "source": ["#Punt Return\n", "number=np.arange(1,12)\n", "fig = plt.figure()\n", "ax = fig.add_subplot(111)\n", "ovr=df_pos_ovr[df_pos_ovr.Return==1]\n", "\n", "ax.axis('off')\n", "\n", "\n", "x=[0,0,0,0,0,0,0,0.2,0.7,0.7,1]\n", "y=[10,9,4,3,2,-2,-3,3,3.5,2.5,3]\n", "\n", "plt.scatter(x,y)\n", "\n", "\n", "plt.tick_params(       \n", "    bottom=False,      \n", "    top=False,        \n", "    labelbottom=False,\n", "    left=False,\n", "    labelleft=False)\n", "\n", "label_x=[0,0,0,0.2]\n", "label_y=[4,3,2,3]\n", "\n", "counter=0\n", "for i,j in zip(label_x,label_y):\n", "    ax.annotate(number[counter], xy=(i,j), xytext=(15,5), textcoords='offset points')\n", "    \n", "    counter+=1\n", "plt.title('Punt Return Formation Proposal');\n", "\n", "#Punt Coverage\n", "number=np.arange(1,12)\n", "fig = plt.figure()\n", "ax = fig.add_subplot(111)\n", "ax.axis('off')\n", "ovr=df_pos_ovr[df_pos_ovr.Return==0]\n", "\n", "x=-0.1,-0.1,-5,-2,-2\n", "y=1,-1,0,1.5,-1.5\n", "\n", "x=[0,0,-0.2,-0.1,0,-0.1,0,0,-2,-2,-5]\n", "y=[10,9,1,0,-1,-2,-9,-10,1.5,-1.5,0]\n", "plt.scatter(x,y,c='g')\n", "\n", "plt.tick_params(       \n", "    bottom=False,      \n", "    top=False,        \n", "    labelbottom=False,\n", "    left=False,\n", "    labelleft=False) \n", "\n", "counter=0\n", "label_x=[-0.2,-0.1,0,-0.1]\n", "label_y=[1,0,-1,-2]\n", "for i,j in zip(label_x,label_y):\n", "    ax.annotate(number[counter], xy=(i,j), xytext=(-20,0), textcoords='offset points')\n", "    \n", "    counter+=1\n", "plt.title('Punt Coverage Formation Proposal');"]}, {"cell_type": "markdown", "metadata": {"_uuid": "f798a373a6b5512e552ce8bcfad345bf235e5402"}, "source": ["### Proposed Solution Consequences:\n", "\n", "\n", "* Would increase the number of fair catches \n", "\n", "\n", "* Should limit the number of punts fielded\n", "\n", "\n", "\n", "* Would limit the number of concussions experienced by the punt returner\n", "\n", "\n", "* More teams will line up players who are not typical blockers or rushers in the gunner position, which would reduce the collision force.\n", "\n", "\n", "* Still gives the punt returner a chance to field the punt so the punt play is still preserved\n", "\n", "\n", "* Less Dense Field in specific parts of the field to avoid accidental collisions between players\n", "\n", "\n", "* Still allows coaches to come up with other punt return/coverage formations that follow the new line of scrimmage rule."]}, {"cell_type": "markdown", "metadata": {"_uuid": "32a85532febfc342a8d3080a8cc99357fe3a827d"}, "source": ["# Conclusion"]}, {"cell_type": "markdown", "metadata": {"_uuid": "702583c33891941dd7542855c3b4266297f7fd10"}, "source": ["* The NFL needs to focus on enforcing stricter penalties for leading with the helmet on contact plays:\n", "    * First review can be done to establish intent of the helmet leading tackle or block of which will either confirm or reverse the call.\n", "    * If a player is charged with two targeting calls, then the player is removed from the game.\n", "\n", "\n", "* The NFL needs to enforce a particular type of punt return or punt coverage formation to reduce the velocities of players on punts:\n", "    * Limit the number of players allowed near the ball snap location to 4 players per team \n"]}], "metadata": {"celltoolbar": "Edit Metadata", "kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4"}}, "nbformat": 4, "nbformat_minor": 1}