{"cells":[{"metadata":{},"cell_type":"markdown","source":"# NFL 1st and Future \nAn injury preventive gameplay EDA\n\nIn this notebook I providde insight on wether type of stadium effects chances of an injury."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pylab as plt\nimport seaborn as sns\nimport matplotlib.patches as patches\nsns.set_style(\"whitegrid\")\n\nimport plotly.graph_objects as go\nfrom plotly.offline import download_plotlyjs, init_notebook_mode,  iplot\ninit_notebook_mode(connected=True)\n\npd.options.mode.chained_assignment = None","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data Prep\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"def reduce_mem_usage(df):\n    \"\"\" iterate through all the columns of a dataframe and modify the data type\n        to reduce memory usage.        \n    \"\"\"\n    start_mem = df.memory_usage().sum() / 1024**2\n    print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))\n    \n    for col in df.columns:\n        col_type = df[col].dtype\n        \n        if col_type != object:\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == 'int':\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)  \n            else:\n                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    df[col] = df[col].astype(np.float64)\n        else:\n            df[col] = df[col].astype('category')\n\n    end_mem = df.memory_usage().sum() / 1024**2\n    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))\n    print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))\n    \n    return df\n\n\ndef import_data(file):\n    \"\"\"create a dataframe and optimize its memory usage\"\"\"\n    df = pd.read_csv(file, parse_dates=True, keep_date_col=True)\n    df = reduce_mem_usage(df)\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# inj = import_data(\"../input/nfl-playing-surface-analytics/InjuryRecord.csv\")\n# playlist = import_data(\"../input/nfl-playing-surface-analytics/PlayList.csv\")\ntrk = import_data(\"../input/nfl-playing-surface-analytics/PlayerTrackData.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trk.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# # Input files\nplaylist = pd.read_csv('../input/nfl-playing-surface-analytics/PlayList.csv')\ninj = pd.read_csv('../input/nfl-playing-surface-analytics/InjuryRecord.csv')\n# trk = pd.read_csv('../input/nfl-playing-surface-analytics/PlayerTrackData.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inj.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"playlist.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(inj.PlayerKey.isnull().sum())\nprint(inj.GameID.isnull().sum())\nprint(inj.PlayKey.isnull().sum())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Seems like there are 28 empty fields in PlayKey column."},{"metadata":{"trusted":true},"cell_type":"code","source":"allplayers = playlist.PlayerKey.nunique()\nallgames = playlist.GameID.nunique()\nallplays = playlist.PlayKey.nunique()\n\nprint('Number of Players: {}'.format(allplayers))\nprint('Number of Games: {}'.format(allgames))\nprint('Number of Plays: {}'.format(allplays))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df1= playlist[['GameID', 'StadiumType', 'FieldType', 'Weather', 'Temperature','Position','RosterPosition','PlayType']].drop_duplicates().reset_index().drop(columns=['index'])\ndf = pd.merge(inj,df1,on='GameID', how='left').drop_duplicates(subset=['GameID']).drop(columns='Surface')\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"The Weather and StadiumType columns have a lot categorical data. \nFor analytic sake I will regroup the data among new labels."},{"metadata":{"trusted":true},"cell_type":"code","source":"df['Weather'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndf['Weather'].replace(['Sunny','Clear','Mostly Sunny','Clear and warm','Fair','Clear Skies','Clear skies','Mostly sunny','Clear and Sunny','Sunny and clear'],['Clear','Clear','Clear','Clear','Clear','Clear','Clear','Clear','Clear','Clear'],inplace=True)\ndf['Weather'].replace(['Cloudy','Partly Cloudy','Cold','Mostly cloudy','Cloudy, 50% change of rain','Coudy','Party Cloudy','Clear and cold','Cloudy and Cool','Sun & clouds'],['Cloudy','Cloudy','Cloudy','Cloudy','Cloudy','Cloudy','Cloudy','Cloudy','Cloudy','Cloudy'],inplace=True)\ndf['Weather'].replace(['Rain','Rain shower','Light Rain','Cloudy with periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph.'],['Rain','Rain','Rain','Rain'],inplace=True)\ndf['Weather'].replace(['Indoor','Indoors','Controlled Climate','N/A (Indoors)'],['Indoor','Indoor','Indoor','Indoor'],inplace=True)\n\nassert df['Weather'].nunique() == 4","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df['StadiumType'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df['StadiumType'].replace(['Outdoors', 'Cloudy', 'Heinz Field','Outdor', 'Ourdoor', 'Outside', 'Outddors','Outdoor Retr Roof-Open', 'Oudoor', 'Bowl'],['Outdoor','Outdoor','Outdoor','Outdoor','Outdoor','Outdoor','Outdoor','Outdoor','Outdoor','Outdoor'],inplace=True)\ndf['StadiumType'].replace(['Indoors', 'Indoor', 'Indoor, Roof Closed', 'Indoor, Roof Closed','Retractable Roof', 'Retr. Roof-Closed', 'Retr. Roof - Closed', 'Retr. Roof Closed'],['Indoor_closed','Indoor_closed','Indoor_closed','Indoor_closed','Indoor_closed','Indoor_closed','Indoor_closed','Indoor_closed'],inplace=True)\ndf['StadiumType'].replace(['Indoor, Open Roof', 'Open', 'Retr. Roof-Open', 'Retr. Roof - Open'],['Indoor_open','Indoor_open','Indoor_open','Indoor_open'],inplace=True)\ndf['StadiumType'].replace(['Dome', 'Domed, closed', 'Closed Dome', 'Domed', 'Dome, closed'],['Dome_closed','Dome_closed','Dome_closed','Dome_closed','Dome_closed'],inplace=True)\n# df['StadiumType'].replace(['Domed, Open', 'Domed, open'],['Dome_open','Dome_open'],inplace=True)\n# df['StadiumType'].value_counts()\nassert df['StadiumType'].nunique() == 4","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Analytics I\nFor first part analytics only use Playlist data and InjuryRecord. \nMy hypothesis is that closed/indoor stadiums have less occurance of number of injuries.\nIf true, research goes deeper in finding reasons why."},{"metadata":{"trusted":true},"cell_type":"code","source":"df.groupby('FieldType').count()['PlayerKey'] \\\n    .sort_values() \\\n    .plot(kind='bar', figsize=(15, 5), title='Count of Field Surface in Injury cases', color = 'green')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.groupby('RosterPosition').count()['PlayerKey'] \\\n    .sort_values() \\\n    .plot(kind='barh', figsize=(15, 5), title='Count of injuries by Stadium Type', color='blue')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.groupby('PlayType').count()['PlayerKey'] \\\n    .sort_values() \\\n    .plot(kind='barh', figsize=(15, 5), title='Count of injuries by Stadium Type', color='orange')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.groupby('Weather').count()['PlayerKey'] \\\n    .sort_values() \\\n    .plot(kind='barh', figsize=(15, 5), title='Count of injuries by Weather type', color='red')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"These first plots trigger me to investigate combinations of features.\nDo we see higher county of injuries in a certain combination?"},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.set(style='darkgrid')\nsns.catplot(y=\"StadiumType\",\n              hue=\"FieldType\",\n              data=df, kind=\"count\",\n            height=6);\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nsns.set(style='darkgrid')\nsns.catplot(y=\"StadiumType\",\n              hue=\"FieldType\", col=\"Weather\",\n              data=df, kind=\"count\",\n            height=6)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"I will focus on Outdoor and Indoor closed as the other StadiumType do not have significant counts."},{"metadata":{"trusted":true},"cell_type":"code","source":"dfst=df[df['StadiumType']==\"Outdoor\"]\nsns.set(style='darkgrid')\nsns.catplot(y=\"PlayType\",\n              hue=\"FieldType\", col=\"Weather\",\n              data=dfst, kind=\"count\",\n            height=6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Note only synthetic field applicable in this case.\ndfic=df[df['StadiumType']==\"Indoor_closed\"]\nsns.set(style='darkgrid')\nsns.catplot(y=\"PlayType\",\n              hue=\"Weather\", col=\"FieldType\",\n              data=dfic, kind=\"count\",\n            height=6)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Outdoor Synthetic: Most injuries at Rush.\nOutdoor Natural: Most injuries at Rush, Kickoff and Pass.\n\nIndoor Synthetic: Most injuries occur at Rush and Pass.\nIndoor Natural: None."},{"metadata":{},"cell_type":"markdown","source":"Let us take a look at severity of injuries\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"dfo = df[df[\"StadiumType\"]==\"Outdoor\"]\ndfom42=dfo[dfo['DM_M42']==1]\ndfom28=dfo[dfo['DM_M28']==1]\ndfom7=dfo[dfo['DM_M7']==1]\ndfom1=dfo[dfo['DM_M1']==1]\ng=sns.catplot(y=\"RosterPosition\", hue=\"PlayType\", col=\"FieldType\", data=dfom42, kind=\"count\")\ng.set_titles(\"M42 {col_name} {col_var}\")\nh=sns.catplot(y=\"RosterPosition\", hue=\"PlayType\",  col=\"FieldType\",data=dfom28, kind=\"count\")\nh.set_titles(\"M28 {col_name} {col_var}\")\nh1=sns.catplot(y=\"RosterPosition\", hue=\"PlayType\",  col=\"FieldType\",data=dfom7, kind=\"count\")\nh1.set_titles(\"M7 {col_name} {col_var}\")\nh2=sns.catplot(y=\"RosterPosition\", hue=\"PlayType\",  col=\"FieldType\",data=dfom1, kind=\"count\")\nh2.set_titles(\"M1 {col_name} {col_var}\")\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dficm42=dfic[dfic['DM_M42']==1]\ndficm28=dfic[dfic['DM_M28']==1]\ndficm7=dfic[dfic['DM_M7']==1]\ndficm1=dfic[dfic['DM_M1']==1]\nsns.catplot(y=\"RosterPosition\", hue=\"PlayType\", data=dficm42, kind=\"count\")\nplt.title('Injury M42', fontsize=16)\nsns.catplot(y=\"RosterPosition\", hue=\"PlayType\", data=dficm28, kind=\"count\")\nplt.title('Injury M28', fontsize=16)\nsns.catplot(y=\"RosterPosition\", hue=\"PlayType\", data=dficm7, kind=\"count\")\nplt.title('Injury M7', fontsize=16)\nsns.catplot(y=\"RosterPosition\", hue=\"PlayType\", data=dficm1, kind=\"count\")\nplt.title('Injury M1', fontsize=16)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dfst=df[df['StadiumType']==\"Outdoor\"]\nsns.set(style='darkgrid')\ng=sns.catplot(y=\"BodyPart\",\n              hue=\"Weather\", col=\"FieldType\",\n              data=dfst, kind=\"count\",\n            height=6)\ng.set_titles(\"Outdoor, {col_name} {col_var}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Note only synthetic field applicable in this case.\ndfic=df[df['StadiumType']==\"Indoor_closed\"]\nsns.set(style='darkgrid')\ng=sns.catplot(y=\"BodyPart\",\n              hue=\"Weather\", col=\"FieldType\",\n              data=dfic, kind=\"count\",\n            height=6)\ng.set_titles(\"Indoor_closed, {col_name} {col_var}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"****Temperature and injury counts****\n\nAre there bodypart injuries that occur at certain temperatures?\nAnd are there changes between outdoor and indoor?"},{"metadata":{"trusted":true},"cell_type":"code","source":"dfo.drop(dfo.loc[dfo.Temperature==-999].index, inplace=True)\nplt.hist(dfo.Temperature.values, normed=False, bins=30)\nplt.xlabel('Temp (F)');\nplt.ylabel('Count Injuries');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axs = plt.subplots(3,2,figsize=(25,15))\nbplist=['Ankle','Heel','Foot','Knee','Toes']\nfor i, v in enumerate(bplist):\n    sns.distplot(dfst[dfst.BodyPart == 'Ankle'].Temperature, ax = axs[0,0], label=dfst[dfst.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[0,0].set_title('Temperature for Ankle injuries')\n    sns.distplot(dfst[dfst.BodyPart == 'Knee'].Temperature, ax = axs[0,1], label=dfst[dfst.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[0,1].set_title('Temperature for Knee injuries')\n    sns.distplot(dfst[dfst.BodyPart == 'Heel'].Temperature, ax = axs[1,0], label=dfst[dfst.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[1,0].set_title('Temperature for Heel injuries')\n    sns.distplot(dfst[dfst.BodyPart == 'Toes'].Temperature, ax = axs[1,1], label=dfst[dfst.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[1,1].set_title('Temperature for Toes injuries')\n    sns.distplot(dfst[dfst.BodyPart == 'Foot'].Temperature, ax = axs[2,0], label=dfst[dfst.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[2,0].set_title('Temperature for Foot injuries')\nplt.legend()    \nplt.suptitle('Histogram temperature distribution for bodypart injuries', fontsize=16)\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dfic.drop(dfic.loc[dfic.Temperature==-999].index, inplace=True)\nplt.hist(dfic.Temperature.values, bins=30)\nplt.xlabel('Temp (F)');\nplt.ylabel('Count Injuries');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, axs = plt.subplots(3,2,figsize=(25,15))\nbplist=['Ankle','Heel','Foot','Knee','Toes']\nfor i, v in enumerate(bplist):\n    sns.distplot(dfic[dfic.BodyPart == 'Ankle'].Temperature, ax = axs[0,0], label=dfic[dfic.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[0,0].set_title('Temperature for Ankle injuries')\n    sns.distplot(dfic[dfic.BodyPart == 'Knee'].Temperature, ax = axs[0,1], label=dfic[dfic.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[0,1].set_title('Temperature for Knee injuries')\n    sns.distplot(dfic[dfic.BodyPart == 'Heel'].Temperature, ax = axs[1,0], label=dfic[dfic.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[1,0].set_title('Temperature for Heel injuries')\n    sns.distplot(dfic[dfic.BodyPart == 'Toes'].Temperature, ax = axs[1,1], label=dfic[dfic.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[1,1].set_title('Temperature for Toes injuries')\n    sns.distplot(dfic[dfic.BodyPart == 'Foot'].Temperature, ax = axs[2,0], label=dfic[dfic.BodyPart == v],\n                         kde=False,\n                         bins=30)\n    axs[2,0].set_title('Temperature for Foot injuries')\nplt.legend()    \nplt.suptitle('Histogram temperature distribution for bodypart injuries', fontsize=16)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Although it is visible that more Ankle, Knee and Toes injuries occur at the extreme low or high temperatures,\nthere is no hard evidence that certain BodyPart have a higher count of injuries at certain temperatures.\n"},{"metadata":{},"cell_type":"markdown","source":"# Analysis II: Speed, Acceleration and Jerk\n"},{"metadata":{},"cell_type":"markdown","source":"In this section I go into my final hypothesis, which involves jerk.\n\nSynthetic turf shows higher jerk magnitude than natural turf.\n\nInjuries on synthetic turf will therefore show a higher jerk magnitude, causing more severe injuries.\n\n\nFirst of all what is jerk?\nIn mathematical terms it is the derivative of acceleration.\n\nLet me give a practical explanation of jerk:\nAn experienced driver gradually applies the brakes, causing a slowly increasing deceleration (small jerk). An inexperienced driver, or a driver responding to an emergency, applies the brakes suddenly, causing a rapid increase in deceleration (large jerk). The sensation of jerk is noticeable, causing the passenger’s head to jerk forward.\n\nSource https://www.physicsforums.com/threads/what-is-jerk-and-jounce-conceptually.716152/\n\n"},{"metadata":{},"cell_type":"markdown","source":"Note: Looks like an injury is always after one big acceleration. Never more than 1 big acceleration."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Calculate acceleration\ntrk['a'] = (trk.s - trk.s.shift(1)) / (trk.time - trk.time.shift(1))\n\n# Calculate instantaneous jerk\ntrk['j'] = (trk.a - trk.a.shift(1)) / (trk.time - trk.time.shift(1))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In next blocks I take a look at some PlayKey where the first plots show speed, acceleration and jerk before injury.\nAnd in the last plot (far right one) I take a look at the injury PlayKey.\nMy hypothesis is that jerk will show a calm pattern in pre-injury PlayKeys and a rough pattern in injury PlayKeys.\nNote that I used a moving average filtering on jerk."},{"metadata":{"trusted":true},"cell_type":"code","source":"def movingaverage(interval, window_size):\n    window = np.ones(int(window_size))/float(window_size)\n    return np.convolve(interval, window, 'same')\n\n# movingaverage(,2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# idlist=['39873-4-1', '39873-4-2', '39873-4-3', '39873-4-4', '39873-4-5',\n#        '39873-4-6', '39873-4-7', '39873-4-8', '39873-4-9', '39873-4-10',\n#        '39873-4-11', '39873-4-12', '39873-4-13', '39873-4-14',\n#        '39873-4-15', '39873-4-16', '39873-4-17', '39873-4-18',\n#        '39873-4-19', '39873-4-20', '39873-4-21', '39873-4-22',","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Find the PlayKey marked as injury for that GameID\ninj[inj.GameID=='39873-4'].PlayKey.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#In this case '39873-4-32'is PlayKey marked as injury, all the other PlayKey show a more stationary pattern of jerk.\nidlist=['39873-4-23', '39873-4-24', '39873-4-25', '39873-4-26',\n       '39873-4-27', '39873-4-28', '39873-4-29', '39873-4-30',\n       '39873-4-31', '39873-4-32']\n# len(idlist)\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,2), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# inj[inj.GameID=='39671-12'].head()\nlist(playlist[playlist.GameID=='39671-12'].PlayKey.unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Now look into a player on natural field with severe injury plot in last plot\n#This is an NaN example, however you can quite easily spot plot with the injury data. This time it is not the last one, but second last.\n# idlist = list(playlist[playlist.GameID=='39671-12'].PlayKey.unique())\nidlist = ['39671-12-19',\n '39671-12-20',\n '39671-12-21',\n '39671-12-22',\n '39671-12-23',\n '39671-12-24']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\n# modes = ['full', 'same', 'valid']\n\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# dfs42[dfs42.PlayKey=='44492-3-23'].head()\nlist(playlist[playlist.GameID=='44492-3'].PlayKey.unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#In this case the player injury is noted with playkey 44492-3-23. Data suggest that player is still playing, probably injured, in later playkeys 24 and 25 after which jerk normalizes onwards from playkey 26 and 27.\n\n# idlist=[ '44492-3-19',\n#  '44492-3-20',\n#  '44492-3-21',\n#  '44492-3-22',\n#  '44492-3-23']\nidlist=['44492-3-23',\n '44492-3-24',\n '44492-3-25',\n '44492-3-26',\n '44492-3-27']\n\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In next two codeblocks I inspect all PlayKeys on Natural Turf that show severe injuries (M42=True). \nFrom the earlier examples I expect that all will show a remarkable pattern."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Find a PlayKey of injured player on natural turf\ndfsn = df[df.FieldType=='Natural']\ndfs42= dfsn[dfsn.DM_M42==1]\nlist(dfs42.PlayKey.dropna().unique())\n# dfs42[dfs42.GameID=='33337-2'].PlayKey.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#All severe injury(M42=1) plays on natural turf \nidlist=['36621-13-58',\n '43505-2-49',\n '41094-1-55',\n '44434-10-31',\n '31070-3-7']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n#                 s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n#                 a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys for Natural turf', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In next two codeblocks I inspect all PlayKeys on Synthetic Turf that show severe injuries (M42=True). \nFrom the earlier examples I expect that all will show a remarkable pattern."},{"metadata":{"trusted":true},"cell_type":"code","source":"#Find a PlayKey of injured player on synthetic\ndfss = df[df.FieldType=='Synthetic']\ndfs42= df[df.DM_M42==1]\nlist(dfs42.PlayKey.dropna().unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#All severe injury(M42=1) plays on synthetic field \nidlist=['39873-4-32',\n '36557-1-70',\n '43532-5-69',\n '46014-10-22',\n '46331-4-44']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n#                 s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n#                 a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys for Synthetic turf', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"It is hard to interpret jerk, however in many cases jerk magnitude shows a calm signal when players are not injured.\nPlayKeys noted as injury and PlayKeys shortly before or after,show a rough pattern of jerk magnitude.\nAlthough proof is not watertide is gives enough evidence for further investigation into jerk and probability of a player being injured.\n\nFocusing on differences between synthetic and natural turf it can be seen that natural turf shows a more stationary signal than synthetic turf, meaning in natural turf you see more timesegments where the amplitude of jerk does not go higher or lower than -1 or 1. \nHowever jerk signals from both turf show remarkable difference between injury and non-injury PlayKeys.\n\nNext we look at difference in Jerk Magnitude for different BodyPart injuries.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"dfss = df[df.FieldType=='Synthetic']\ndfskn= dfss[dfss.BodyPart=='Knee']\ndfsan= dfss[dfss.BodyPart=='Ankle']\ndfsto= dfss[dfss.BodyPart=='Toes']\ndfsfo= dfss[dfss.BodyPart=='Foot']\ndfshe= dfss[dfss.BodyPart=='Heel']\nlist(dfsan.PlayKey.dropna().unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Some Knee injury PlayKeys on synthetic field \nidlist=[ '42398-15-33',\n '47220-4-16',\n '44482-20-21',\n '36607-16-19',\n '47307-10-18']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys of Knee injuries', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Some Foot injury PlayKeys on synthetic field \nidlist=[ '38364-5-23', '47235-7-55']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys of Foot injuries', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Some Ankle injury PlayKeys on synthetic field \nidlist=['36557-1-70',\n '43532-5-69',\n '46014-10-22',\n '45962-8-40',\n '46331-4-44',]\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys of Ankle injuries', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Some more for natural turf per Bodypart"},{"metadata":{"trusted":true},"cell_type":"code","source":"dfsn = df[df.FieldType=='Natural']\ndfskn= dfsn[dfsn.BodyPart=='Knee']\ndfsan= dfsn[dfsn.BodyPart=='Ankle']\ndfsto= dfsn[dfsn.BodyPart=='Toes']\ndfsfo= dfsn[dfsn.BodyPart=='Foot']\ndfshe= dfsn[dfsn.BodyPart=='Heel']\nlist(dfshe.PlayKey.dropna().unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idlist=['46646-3-30',\n '44492-3-23',\n '41943-1-12',\n '45950-8-18',\n '43540-3-14']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys of Ankle injuries', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idlist=['46074-7-26',\n '41145-2-60',\n '44860-5-52',\n '41094-1-55',\n '46119-3-16']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys of Knee injuries', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idlist=['36621-13-58', '43505-2-49', '44434-10-31', '33337-8-15']\nnumber_of_subplots=len(idlist)\nfig,ax = plt.subplots(1,number_of_subplots,figsize=(30,10),sharey=True)\nfor j, pk in enumerate(idlist):\n    for i,v, in enumerate(range(number_of_subplots)):\n            if i<=number_of_subplots:\n                s1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].s, data=trk, ax=ax[j], color='blue', label='Speed {:}'.format(idlist[i]) if i==j else '')\n                a1=sns.lineplot(trk[trk.PlayKey == pk].time, trk[trk.PlayKey == pk].a, data=trk, ax=ax[j], color='orange', label='Acceleration {:}'.format(idlist[i]) if i==j else '')\n                j1=sns.lineplot(trk[trk.PlayKey == pk].time, movingaverage(trk[trk.PlayKey == pk].j,5), data=trk, ax=ax[j], color='red', label='Jerk {:}'.format(idlist[i]) if i==j else '')          \n                i = i+1\n    j = j+1\nplt.suptitle('Speed, Acceleration, Jerk for different PlayKeys of Foot injuries', fontsize=16)    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Note that heel and toes injuries are available show NaN for both synthetic as natural turf data and are therefore no be used for this analysis."},{"metadata":{},"cell_type":"markdown","source":"# Conclusion\n\nWe have seen a lot of plots and data insights. This notebook provides you knowlegde that in most cases players with an injury show at those PlayKeys high spikes in jerk magnitude for a short period of time compared to non injury PlayKeys.\nFurthermore a difference between synthetic and natural turf is visible, namely jerk magnitude of players on natural turf show a more stationary jerk magnitude (amplitude spikes to not pass -1 or +1 for long periods of time).\n\nWhat can you do as NFL team with the insights of this notebook?\nDetermine muscle fatique and thus risk of injuries by the use of your players speed, acceleration and jerk magnitude data.\nSee following research: Amir Baghdadi, Fadel M. Megahed, Ehsan T. Esfahani & Lora A. Cavuoto\n(2018): A machine learning approach to detect changes in gait parameters following a fatiguing\noccupational task, Ergonomics, DOI: 10.1080/00140139.2018.1442936\n\nMore advanced research needed, however plausible:\nCalculate probability of injury using acceleration and jerk magnitude data to determine play quality of natural or synthetic turfs in different weather conditions."}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":1}