{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# NFL Playing Surface Data Analysis\n\nAnalysis of three datasets related to the effects that playing on synthetic turf versus natural turf can have on player movements and the factors that may contribute to lower extremity injuries. \n\nThe data provided for analysis are 250 complete player in-game histories from two subsequent NFL regular seasons. Three different files in .csv format are provided, documenting injuries, player-plays, and player movement during plays:\n\n- Injury Record: The injury record file in .csv format contains information on 105 lower-limb injuries that occurred during regular season games over the two seasons. Injuries can be linked to specific records in a player's history using the PlayerKey, GameID, and PlayKey fields.\n\n- Play List: – The play list file contains the details for the 267,005 player-plays that make up the dataset. Each player is indexed by PlayerKey, GameID, and PlayKey fields. Details about the game and play include the player’s assigned roster position, stadium type, field type, weather, play type, position for the play, and position group.\n\n- Player Track Data: player level data that describes the location, orientation, speed, and direction of each player during a play recorded at 10 Hz (i.e. 10 observations recorded per second).","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:42:40.708345Z","iopub.execute_input":"2021-09-20T17:42:40.708820Z","iopub.status.idle":"2021-09-20T17:42:41.651904Z","shell.execute_reply.started":"2021-09-20T17:42:40.708681Z","shell.execute_reply":"2021-09-20T17:42:41.651118Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"injury_df = pd.read_csv('../input/nfl-playing-surface-analytics/InjuryRecord.csv')","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:42:59.341228Z","iopub.execute_input":"2021-09-20T17:42:59.341594Z","iopub.status.idle":"2021-09-20T17:42:59.361879Z","shell.execute_reply.started":"2021-09-20T17:42:59.341559Z","shell.execute_reply":"2021-09-20T17:42:59.360917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"play_list_df = pd.read_csv('../input/nfl-playing-surface-analytics/PlayList.csv')","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:43:00.825085Z","iopub.execute_input":"2021-09-20T17:43:00.825429Z","iopub.status.idle":"2021-09-20T17:43:01.642866Z","shell.execute_reply.started":"2021-09-20T17:43:00.825397Z","shell.execute_reply":"2021-09-20T17:43:01.641912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"player_track_df = pd.read_csv('../input/nfl-playing-surface-analytics/PlayerTrackData.csv')","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:43:03.284345Z","iopub.execute_input":"2021-09-20T17:43:03.284680Z","iopub.status.idle":"2021-09-20T17:44:48.465201Z","shell.execute_reply.started":"2021-09-20T17:43:03.284650Z","shell.execute_reply":"2021-09-20T17:44:48.463671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"injury_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:45:06.067597Z","iopub.execute_input":"2021-09-20T17:45:06.067993Z","iopub.status.idle":"2021-09-20T17:45:06.105370Z","shell.execute_reply.started":"2021-09-20T17:45:06.067952Z","shell.execute_reply":"2021-09-20T17:45:06.104272Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"play_list_df.head()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:45:23.356043Z","iopub.execute_input":"2021-09-20T17:45:23.356398Z","iopub.status.idle":"2021-09-20T17:45:23.375432Z","shell.execute_reply.started":"2021-09-20T17:45:23.356365Z","shell.execute_reply":"2021-09-20T17:45:23.373994Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"player_track_df.head(15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:45:23.983648Z","iopub.execute_input":"2021-09-20T17:45:23.984002Z","iopub.status.idle":"2021-09-20T17:45:24.008921Z","shell.execute_reply.started":"2021-09-20T17:45:23.983967Z","shell.execute_reply":"2021-09-20T17:45:24.007541Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Cleaning and Preparation\nIn this stage the data is checked for accuracy and completeness prior to beginning the analysis. \n\n- Remove extraneous data\n- Check for in missing values\n- Replace missing values\n- Delete data that cannot be corrected/replaced\n- Correct any data formatting issues\n- Creating new features\n- Identify errors revealed when new variables are created\n\n## Removing Extraneous Data\n\n### Play List","metadata":{}},{"cell_type":"code","source":"play_list_df.info()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:45:47.424680Z","iopub.execute_input":"2021-09-20T17:45:47.425037Z","iopub.status.idle":"2021-09-20T17:45:47.602821Z","shell.execute_reply.started":"2021-09-20T17:45:47.425001Z","shell.execute_reply":"2021-09-20T17:45:47.601748Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are a significant number of rows in play_list_df. We are concerned primarily with the plays associated with injuries. Therefore, we will identify and delete the irrelevant data.","metadata":{}},{"cell_type":"code","source":"#Number of unique PlayKeys in Player List\nlen(pd.unique(play_list_df['PlayKey']))","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:45:59.962703Z","iopub.execute_input":"2021-09-20T17:45:59.963065Z","iopub.status.idle":"2021-09-20T17:46:00.020201Z","shell.execute_reply.started":"2021-09-20T17:45:59.963032Z","shell.execute_reply":"2021-09-20T17:46:00.019217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Identifying plays in Player List associated with plays in Injury Record\nplay_list_df.PlayKey.isin(injury_df.PlayKey).value_counts()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:46:01.278403Z","iopub.execute_input":"2021-09-20T17:46:01.278751Z","iopub.status.idle":"2021-09-20T17:46:01.319089Z","shell.execute_reply.started":"2021-09-20T17:46:01.278712Z","shell.execute_reply":"2021-09-20T17:46:01.318033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Identifying plays in Player List associated with plays in Injury Record\nplay_list_df.GameID.isin(injury_df.PlayKey).value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:02.871733Z","iopub.execute_input":"2021-09-20T17:46:02.872133Z","iopub.status.idle":"2021-09-20T17:46:02.893541Z","shell.execute_reply.started":"2021-09-20T17:46:02.872095Z","shell.execute_reply":"2021-09-20T17:46:02.892642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are only <b>76</b> PlayKeys in the player_track_df that are associated with plays in injury records. Therefore, these are the rows containing data on the plays where the injury occured. \n\n#### Removing Irrelevant Rows","metadata":{}},{"cell_type":"code","source":"#Dropping rows where PlayKey is not in Injury Record \nplay_list_df.drop(play_list_df[play_list_df.PlayKey.isin(injury_df.PlayKey) == False].index,inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:06.777103Z","iopub.execute_input":"2021-09-20T17:46:06.777418Z","iopub.status.idle":"2021-09-20T17:46:06.914266Z","shell.execute_reply.started":"2021-09-20T17:46:06.777388Z","shell.execute_reply":"2021-09-20T17:46:06.913299Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Player Track Data","metadata":{}},{"cell_type":"code","source":"player_track_df.info()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:08.356658Z","iopub.execute_input":"2021-09-20T17:46:08.357597Z","iopub.status.idle":"2021-09-20T17:46:08.369552Z","shell.execute_reply.started":"2021-09-20T17:46:08.357552Z","shell.execute_reply":"2021-09-20T17:46:08.368417Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are a significant number of rows in player_track_df. We are concerned primarily with the plays associated with injuries. Therefore, we will identify and delete the irrelevant data.","metadata":{}},{"cell_type":"code","source":"#Number of unique PlayKeys in Player Track Data\nlen(pd.unique(player_track_df['PlayKey']))","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:19.705273Z","iopub.execute_input":"2021-09-20T17:46:19.705551Z","iopub.status.idle":"2021-09-20T17:46:24.376007Z","shell.execute_reply.started":"2021-09-20T17:46:19.705524Z","shell.execute_reply":"2021-09-20T17:46:24.375029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Identifying plays in Player Track Data associated with plays in Injury Record\nplayer_track_df.PlayKey.isin(injury_df.PlayKey).value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:24.377457Z","iopub.execute_input":"2021-09-20T17:46:24.377766Z","iopub.status.idle":"2021-09-20T17:46:27.954560Z","shell.execute_reply.started":"2021-09-20T17:46:24.377725Z","shell.execute_reply":"2021-09-20T17:46:27.953805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are only <b>21905</b> rows in the player_track_df that are associated with plays in the injury record. Therefore, these are the rows containing data on the plays where the injury occured. ","metadata":{}},{"cell_type":"code","source":"#Dropping rows where PlayKey is not in Injury Record \nplayer_track_df.drop(player_track_df[player_track_df.PlayKey.isin(injury_df.PlayKey) == False].index,inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:27.956043Z","iopub.execute_input":"2021-09-20T17:46:27.956274Z","iopub.status.idle":"2021-09-20T17:46:50.981964Z","shell.execute_reply.started":"2021-09-20T17:46:27.956248Z","shell.execute_reply":"2021-09-20T17:46:50.981242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Number of unique PlayKeys in Player List\nlen(pd.unique(player_track_df['PlayKey']))","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:50.983368Z","iopub.execute_input":"2021-09-20T17:46:50.984289Z","iopub.status.idle":"2021-09-20T17:46:50.992249Z","shell.execute_reply.started":"2021-09-20T17:46:50.984244Z","shell.execute_reply":"2021-09-20T17:46:50.991563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Checking for missing values\n\n### Injury Record","metadata":{}},{"cell_type":"code","source":"#Checking for any missing values\ninjury_df.isnull().values.any()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:46:50.993294Z","iopub.execute_input":"2021-09-20T17:46:50.993491Z","iopub.status.idle":"2021-09-20T17:46:51.009940Z","shell.execute_reply.started":"2021-09-20T17:46:50.993468Z","shell.execute_reply":"2021-09-20T17:46:51.008816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Identifying which columns contain missing values\ninjury_df.info()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:46:59.628316Z","iopub.execute_input":"2021-09-20T17:46:59.629370Z","iopub.status.idle":"2021-09-20T17:46:59.645077Z","shell.execute_reply.started":"2021-09-20T17:46:59.629320Z","shell.execute_reply":"2021-09-20T17:46:59.643955Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are missing values in the \"PlayKey\" Column. \n\nPlayKey uniquely identifies plays made by a specific player during a certain game. Missing values mean that there are injuries recorded that are not associated with a specific play during that player's game. Additionally we will not have information on the play from the Play List and Player Track Data. \n\nAnother thing to note is that there are only 76 unique PlayKeys in the player_track_df and play_list_df that are associated with plays in injury records. Therefore, there is no associated data for the associated rows with missing PLayKeys in injury_df. \n\nTherefore, it would be best to drop these rows that do not contain associated values in the other two Dataframe.  ","metadata":{}},{"cell_type":"markdown","source":"#### Deleting Rows Associated with the Missing Values","metadata":{}},{"cell_type":"code","source":"#Dropping rows with missing values\ninjury_df.dropna(inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:07.385401Z","iopub.execute_input":"2021-09-20T17:47:07.385979Z","iopub.status.idle":"2021-09-20T17:47:07.393047Z","shell.execute_reply.started":"2021-09-20T17:47:07.385929Z","shell.execute_reply":"2021-09-20T17:47:07.392175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Checking if any missing values remain\ninjury_df.isnull().values.any()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:07.808660Z","iopub.execute_input":"2021-09-20T17:47:07.809578Z","iopub.status.idle":"2021-09-20T17:47:07.816823Z","shell.execute_reply.started":"2021-09-20T17:47:07.809535Z","shell.execute_reply":"2021-09-20T17:47:07.815874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Play List","metadata":{}},{"cell_type":"code","source":"#Checking for any missing values\nplay_list_df.isnull().values.any()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:47:09.727473Z","iopub.execute_input":"2021-09-20T17:47:09.727817Z","iopub.status.idle":"2021-09-20T17:47:09.735229Z","shell.execute_reply.started":"2021-09-20T17:47:09.727763Z","shell.execute_reply":"2021-09-20T17:47:09.734361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"play_list_df.info()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:10.153765Z","iopub.execute_input":"2021-09-20T17:47:10.154174Z","iopub.status.idle":"2021-09-20T17:47:10.168453Z","shell.execute_reply.started":"2021-09-20T17:47:10.154116Z","shell.execute_reply":"2021-09-20T17:47:10.167737Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The \"StadiumType\" and \"Weather\" have missing values.\n- For missing stadium type values,we will assume the stadium type is either unknown or does not fit into the preset categories (For example, partially Indoors) and represent the value as \"Unknown.\"\n- For missing weather values, we will assume the game occured in either closed dome/indoor stadium or the weather conditions are not known and represent the value as \"Not Applicable.\"","metadata":{}},{"cell_type":"markdown","source":"#### Replacing the Missing Values","metadata":{}},{"cell_type":"code","source":"play_list_df['StadiumType'] = play_list_df['StadiumType'].fillna(\"Unknown\")\nplay_list_df['Weather'] = play_list_df['Weather'].fillna(\"Not Applicable\")","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:28.463311Z","iopub.execute_input":"2021-09-20T17:47:28.464291Z","iopub.status.idle":"2021-09-20T17:47:28.471102Z","shell.execute_reply.started":"2021-09-20T17:47:28.464248Z","shell.execute_reply":"2021-09-20T17:47:28.470237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Checking if any missing values remain\nplay_list_df.isnull().values.any()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:29.078526Z","iopub.execute_input":"2021-09-20T17:47:29.078849Z","iopub.status.idle":"2021-09-20T17:47:29.086732Z","shell.execute_reply.started":"2021-09-20T17:47:29.078794Z","shell.execute_reply":"2021-09-20T17:47:29.085711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Player Track Data","metadata":{}},{"cell_type":"code","source":"#Checking for any missing values\nplayer_track_df.isnull().values.any()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:31.438903Z","iopub.execute_input":"2021-09-20T17:47:31.439190Z","iopub.status.idle":"2021-09-20T17:47:31.448816Z","shell.execute_reply.started":"2021-09-20T17:47:31.439163Z","shell.execute_reply":"2021-09-20T17:47:31.448153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Identifying which columns contain missing values\nplayer_track_df.isnull().value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:32.476801Z","iopub.execute_input":"2021-09-20T17:47:32.477838Z","iopub.status.idle":"2021-09-20T17:47:32.501851Z","shell.execute_reply.started":"2021-09-20T17:47:32.477798Z","shell.execute_reply":"2021-09-20T17:47:32.500974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see that the \"event\" column has missing values.\n\nThe event refers to the play details as a function of time during the play. For each play, each subsequent value in this column is a moment in time during the play. Therefore, it is possible the name of the event only appears on the first instant of the play (time = 0.0) and remains blank in the subsequent rows associated with the same event. Nevertheless, we will be dropping the column as it mainly contains categorical data and we will still have all the numeric data available for analysis.","metadata":{}},{"cell_type":"markdown","source":"#### Dropping Missing Values","metadata":{}},{"cell_type":"code","source":"#Dropping the \"event\" column\nplayer_track_df.drop('event', inplace=True, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:37.609837Z","iopub.execute_input":"2021-09-20T17:47:37.610493Z","iopub.status.idle":"2021-09-20T17:47:37.619195Z","shell.execute_reply.started":"2021-09-20T17:47:37.610446Z","shell.execute_reply":"2021-09-20T17:47:37.618505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Checking if any missing values remain\nplayer_track_df.isnull().values.any()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:47:38.099489Z","iopub.execute_input":"2021-09-20T17:47:38.100437Z","iopub.status.idle":"2021-09-20T17:47:38.109389Z","shell.execute_reply.started":"2021-09-20T17:47:38.100391Z","shell.execute_reply":"2021-09-20T17:47:38.108443Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Correct Formatting Issues\n### Play List\n#### Stadium Type","metadata":{}},{"cell_type":"code","source":"play_list_df['StadiumType'].value_counts()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:47:40.765978Z","iopub.execute_input":"2021-09-20T17:47:40.766341Z","iopub.status.idle":"2021-09-20T17:47:40.775909Z","shell.execute_reply.started":"2021-09-20T17:47:40.766302Z","shell.execute_reply":"2021-09-20T17:47:40.775055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Generally , we are only concerned if the Stadium is indoor or outdoor to understand its exposure to the elements.\n\nThe inconsistencies in the stadium types will all be attributed as follows:\n- Outdoor: Outdoors; Oudoor,Outddors; Retr. Roof - Open; Open; Retr. Roof - Open; Indoor, Roof Closed  \n- Indoor: Indoors; Retr. Roof-Closed; Retr. Roof - Closed; Roof Closed; Dome; Domed, closed; Closed Dome; Indoor, Roof Closed   \n\nThe following are in and Unknown State so we will classify them all as Unknown\n- Unknown: Retractable Roof, Indoor, Open Roof\n","metadata":{}},{"cell_type":"code","source":"#Replacing the values\nplay_list_df['StadiumType'].replace('Outdoors','Outdoor', inplace=True)\nplay_list_df['StadiumType'].replace('Oudoor','Outdoor', inplace=True)\nplay_list_df['StadiumType'].replace('Outddors','Outdoor', inplace=True)\nplay_list_df['StadiumType'].replace('Retr. Roof - Open','Outdoor', inplace=True)\nplay_list_df['StadiumType'].replace('Open','Outdoor', inplace=True)\n\nplay_list_df['StadiumType'].replace('Indoors','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Retr. Roof-Closed','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Retr. Roof - Closed','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Roof Closed','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Indoor, Roof Closed','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Dome','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Domed, closed','Indoor', inplace=True)\nplay_list_df['StadiumType'].replace('Closed Dome','Indoor', inplace=True)\n\nplay_list_df['StadiumType'].replace('Retractable Roof','Unknown', inplace=True)\nplay_list_df['StadiumType'].replace('Indoor, Open Roof','Unknown', inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:42.302048Z","iopub.execute_input":"2021-09-20T17:47:42.302962Z","iopub.status.idle":"2021-09-20T17:47:42.318984Z","shell.execute_reply.started":"2021-09-20T17:47:42.302903Z","shell.execute_reply":"2021-09-20T17:47:42.317762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Weather","metadata":{}},{"cell_type":"code","source":"play_list_df['Weather'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:44.622536Z","iopub.execute_input":"2021-09-20T17:47:44.622870Z","iopub.status.idle":"2021-09-20T17:47:44.631309Z","shell.execute_reply.started":"2021-09-20T17:47:44.622830Z","shell.execute_reply":"2021-09-20T17:47:44.630601Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Generally, we are only concerned about bad weather conditions affecting players such as rain. However, the weather classification appears to be subjective. It may be possible to classify Weather as Hot or Cold based on temperature value but it is not possible to accurately classify if its rainy, cloud etc. given temperature data alone.\n\nBest course of action will be to avoid analyzing data based on 'Weather' in the subsequent analysis. As seen above there are clearly some issues with how the temperature data has been classified under weather. It may be possible to classify Weather as Hot or Cold based on temperature value but it is not possible to accurately classify if it's rainy, cloud etc. given this data.","metadata":{}},{"cell_type":"code","source":"#Dropping the weather column\nplay_list_df.drop(columns=['Weather'],inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:46.368900Z","iopub.execute_input":"2021-09-20T17:47:46.369892Z","iopub.status.idle":"2021-09-20T17:47:46.374658Z","shell.execute_reply.started":"2021-09-20T17:47:46.369821Z","shell.execute_reply":"2021-09-20T17:47:46.373955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Temperature","metadata":{}},{"cell_type":"code","source":"play_list_df['Temperature'].mean()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:47:50.689562Z","iopub.execute_input":"2021-09-20T17:47:50.690370Z","iopub.status.idle":"2021-09-20T17:47:50.697235Z","shell.execute_reply.started":"2021-09-20T17:47:50.690332Z","shell.execute_reply":"2021-09-20T17:47:50.696531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"play_list_df['Temperature'].sort_values()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:47:52.055326Z","iopub.execute_input":"2021-09-20T17:47:52.055937Z","iopub.status.idle":"2021-09-20T17:47:52.064280Z","shell.execute_reply.started":"2021-09-20T17:47:52.055898Z","shell.execute_reply":"2021-09-20T17:47:52.063077Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The temperature values of -999 are clearly wrong. As we see there are some erroneous values so we will replace them with the average of the remaining values. ","metadata":{}},{"cell_type":"code","source":"temp_df = play_list_df['Temperature']\ntemp_df = temp_df.to_frame()\ntemp_df.drop(temp_df[temp_df['Temperature']==-999].index, inplace=True)\navg_temp = round(temp_df['Temperature'].mean())","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:04.615988Z","iopub.execute_input":"2021-09-20T17:48:04.616267Z","iopub.status.idle":"2021-09-20T17:48:04.623585Z","shell.execute_reply.started":"2021-09-20T17:48:04.616242Z","shell.execute_reply":"2021-09-20T17:48:04.622996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"play_list_df['Temperature'].replace(-999,avg_temp ,inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:05.110488Z","iopub.execute_input":"2021-09-20T17:48:05.110949Z","iopub.status.idle":"2021-09-20T17:48:05.114813Z","shell.execute_reply.started":"2021-09-20T17:48:05.110906Z","shell.execute_reply":"2021-09-20T17:48:05.114260Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"play_list_df['Temperature'].mean()","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:06.413752Z","iopub.execute_input":"2021-09-20T17:48:06.414095Z","iopub.status.idle":"2021-09-20T17:48:06.421094Z","shell.execute_reply.started":"2021-09-20T17:48:06.414063Z","shell.execute_reply":"2021-09-20T17:48:06.419745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Exploratory Data Analysis (EDA)\n\nIn this stage, we will examine the data to identify any patterns, trends and relationships between the variables. It will help us analyze the data and extract insights that can be used to make decisions.\n\nData Visualization will give us a clear idea of what the data means by giving it visual context.","metadata":{}},{"cell_type":"markdown","source":"## Injury Records","metadata":{}},{"cell_type":"markdown","source":"### Surface","metadata":{}},{"cell_type":"code","source":"surface_count = injury_df['Surface']\nsns.countplot(x=surface_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Surface\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:09.719662Z","iopub.execute_input":"2021-09-20T17:48:09.720038Z","iopub.status.idle":"2021-09-20T17:48:10.004640Z","shell.execute_reply.started":"2021-09-20T17:48:09.720004Z","shell.execute_reply":"2021-09-20T17:48:10.003649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"synthetic = injury_df['Surface'].value_counts()[0]\nnatural = injury_df['Surface'].value_counts()[1]\n\nround(((synthetic-natural)/natural)*100,2)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:10.588097Z","iopub.execute_input":"2021-09-20T17:48:10.588397Z","iopub.status.idle":"2021-09-20T17:48:10.596726Z","shell.execute_reply.started":"2021-09-20T17:48:10.588366Z","shell.execute_reply":"2021-09-20T17:48:10.595867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Synthetic surfaces result in <b>13.89%</b> more injuries than Natural surfaces. ","metadata":{}},{"cell_type":"markdown","source":"### Body Part Injured","metadata":{}},{"cell_type":"code","source":"bodypart_count = injury_df['BodyPart']\nsns.countplot(x=bodypart_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Body Part\", fontsize=15)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:13.890680Z","iopub.execute_input":"2021-09-20T17:48:13.891421Z","iopub.status.idle":"2021-09-20T17:48:14.109590Z","shell.execute_reply.started":"2021-09-20T17:48:13.891371Z","shell.execute_reply":"2021-09-20T17:48:14.108804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<b>Knee</b> and <b>Ankle</b> injuries have the highest occurrances.","metadata":{}},{"cell_type":"markdown","source":"### Days Missed Due to Injury","metadata":{}},{"cell_type":"markdown","source":"A typical NFL season is 18-weeks or 126 days. Each team plays 17 games with one week off. Therefore, A player would play in one game a week. The number of days missed can be considered the duration of the injury as it affects the players ability to participate in games during the season.\n\n- Injuries lasting 1 days or more can be considered <i>short duration</i>, as the player would miss 1 game or approx. 6% of the season the worst case. \n- Injuries lasting 7 days or more can be considered <i>medium duration</i>, as the player would miss 4 games or approx. 24% of the season in the worst case. \n- Injuries lasting 28 days or more can be considered <i>long duration</i>, as the player would miss 6 games or approx. 35% of the season in the worst case. \n- Injuries lasting 42 days or more can be considered <i>indefinite duration</i>, as the number of games the player would miss would depend on the nature of the injury and whether it would be safe for them to immediately go back to the field. It is entirely possible that the player may have to sit out the rest of the season so injuries in this category are of the greatest concern to players.","metadata":{}},{"cell_type":"code","source":"fig_dims = (8, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\n#Counting Number of Days missed due to injury\nday_1 = injury_df['DM_M1'].value_counts()[1]\ndays_7 = injury_df['DM_M7'].value_counts()[1]\ndays_28 = injury_df['DM_M28'].value_counts()[1]\ndays_42 = injury_df['DM_M42'].value_counts()[1]\n\n#Creating a list with the values\ndays_missed = [day_1,days_7,days_28,days_42]\ndays_missed_label = ['1 Day or More','7 Days or More','28 Days or More','42 Days or More']\n\nplt.bar(days_missed_label,days_missed)\nplt.title(\"Number of Days Missed Due to Injury\", fontsize=20)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:17.225867Z","iopub.execute_input":"2021-09-20T17:48:17.226298Z","iopub.status.idle":"2021-09-20T17:48:17.449797Z","shell.execute_reply.started":"2021-09-20T17:48:17.226255Z","shell.execute_reply":"2021-09-20T17:48:17.448941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The majority of injuries result in players missing either <b>1 or more days or 7 days or more.</b> ","metadata":{}},{"cell_type":"markdown","source":"#### Days Missed Due to Injury vs Surface","metadata":{}},{"cell_type":"code","source":"#Grouping by Surface\ndays_missed_surface = injury_df.groupby('Surface').agg(day_1=('DM_M1',np.count_nonzero),days_7=('DM_M7',np.count_nonzero),days_28=('DM_M28',np.count_nonzero),days_42=('DM_M42',np.count_nonzero))\ndays_missed_surface  ","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:20.258935Z","iopub.execute_input":"2021-09-20T17:48:20.260007Z","iopub.status.idle":"2021-09-20T17:48:20.288692Z","shell.execute_reply.started":"2021-09-20T17:48:20.259955Z","shell.execute_reply":"2021-09-20T17:48:20.287837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The data above has overlap in the values counted as the counts are not mutually exclusive. \n\nIt would be useful to know what percent of players injured on each surface correspond to each injury duration i.e. the days missed. We can modify the days_missed DataFrame to help us visualize this relationship.","metadata":{}},{"cell_type":"code","source":"#Creating new columns with mutually exclusive values\ndays_missed_surface ['day_1_new'] = days_missed_surface ['day_1'] - days_missed_surface ['days_7']\ndays_missed_surface ['days_7_new'] = days_missed_surface ['days_7'] - days_missed_surface ['days_28']\ndays_missed_surface ['days_28_new'] = days_missed_surface ['days_28'] - days_missed_surface ['days_42']\ndays_missed_surface ['days_42_new'] = days_missed_surface ['days_42']\n\n#Deleting the original columns\ndays_missed_surface .drop(['day_1','days_7','days_28','days_42'], inplace=True, axis=1)\n\n#Renaming new columns\ndays_missed_surface.rename(columns={'day_1_new': '1 Day or More', 'days_7_new': '7 Days or More', 'days_28_new': '28 Days or More', 'days_42_new': '42 Days or More'}, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:21.480321Z","iopub.execute_input":"2021-09-20T17:48:21.481090Z","iopub.status.idle":"2021-09-20T17:48:21.495020Z","shell.execute_reply.started":"2021-09-20T17:48:21.481043Z","shell.execute_reply":"2021-09-20T17:48:21.494149Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Plotting the pie chart for each row\ndays_missed_surface.T.plot.pie(subplots=True, figsize=(10, 5), autopct=\"%.1f\", wedgeprops={'linewidth': 3.0, 'edgecolor': 'white'}, labels=None,legend=False)\nplt.legend(labels=days_missed_surface.columns, bbox_to_anchor=(1.05,0.5), loc=\"center right\", fontsize=10,bbox_transform=plt.gcf().transFigure)\n\n#days_missed.T allows us to transpose the DataFrame and plot each row as a pie chart\n# autopct=\"%.1f\" shows the percentage to 1 decimal place \n#wedgeprops={'linewidth': 3.0, 'edgecolor': 'white'} creates a space between pie segments\n#bbox_to_anchor allows us to manually place the legend\n#bbox_transform=plt.gcf().transFigure ensures that the legend does not overlap with the pie charts\n\nplt.title(\"Days Missed Due to Injury vs Surface\", fontsize=20)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:22.429858Z","iopub.execute_input":"2021-09-20T17:48:22.430732Z","iopub.status.idle":"2021-09-20T17:48:22.682369Z","shell.execute_reply.started":"2021-09-20T17:48:22.430674Z","shell.execute_reply":"2021-09-20T17:48:22.681752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Based on this visualization we can say that,\n- Players have a relatively higher likelihood of suffering short and medium duration injuries on Natural surfaces.\n- Players have a relatively higher likelihood of suffering long and indefinite duration injuries on Synthetic surfaces. \n\nOverall, injuries on synthetic surfaces result in players missing more days than those on natural surfaces. \n\n## Play List","metadata":{}},{"cell_type":"markdown","source":"### Roster Position","metadata":{}},{"cell_type":"code","source":"fig_dims = (14, 5)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nroster_position_count = play_list_df['RosterPosition']\nsns.countplot(x=roster_position_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Roster Postion\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:26.147870Z","iopub.execute_input":"2021-09-20T17:48:26.149083Z","iopub.status.idle":"2021-09-20T17:48:26.648075Z","shell.execute_reply.started":"2021-09-20T17:48:26.149019Z","shell.execute_reply":"2021-09-20T17:48:26.647212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The most injuries are sustained by Players in the <b>Linebacker</b> position followed by those in the <b>Wide Receiver</b> and <b>Safety</b> positions.","metadata":{}},{"cell_type":"markdown","source":"### Stadium Type","metadata":{}},{"cell_type":"code","source":"fig_dims = (8, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nstadium_type_count = play_list_df['StadiumType']\nsns.countplot(x=stadium_type_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Stadium Type\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:28.291907Z","iopub.execute_input":"2021-09-20T17:48:28.292901Z","iopub.status.idle":"2021-09-20T17:48:28.499039Z","shell.execute_reply.started":"2021-09-20T17:48:28.292853Z","shell.execute_reply":"2021-09-20T17:48:28.498120Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The most injuries occur in <b>Outdoor</b> Stadiums, which makes sense as these stadiums have the most exposure to potentially hazardous weather conditions.\n\n### Temperature","metadata":{}},{"cell_type":"code","source":"fig_dims = (8, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\ntemp = play_list_df['Temperature']\nsns.histplot(x=temp,binwidth=1)\nplt.title(\"Number of Injury Occurances by Temperature\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:28.914394Z","iopub.execute_input":"2021-09-20T17:48:28.915012Z","iopub.status.idle":"2021-09-20T17:48:29.266104Z","shell.execute_reply.started":"2021-09-20T17:48:28.914972Z","shell.execute_reply":"2021-09-20T17:48:29.265184Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The greatest number of injuries take place in games with weather of <b>67-68 degrees</b> followed by <b>88-89 degrees.</b>\n\n### Position","metadata":{}},{"cell_type":"code","source":"fig_dims = (14, 5)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nposition_count = play_list_df['Position']\nsns.countplot(x=position_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Postion\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:29.581584Z","iopub.execute_input":"2021-09-20T17:48:29.582289Z","iopub.status.idle":"2021-09-20T17:48:29.886807Z","shell.execute_reply.started":"2021-09-20T17:48:29.582249Z","shell.execute_reply":"2021-09-20T17:48:29.885894Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The most injuries are sustained by players in the <b>Wide Receiver (WR)</b> position during a play followed by those in the <b>Outside Linebacker (OLB)</b> position.\n\n### Position Group","metadata":{}},{"cell_type":"code","source":"fig_dims = (14, 5)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nposition_group_count = play_list_df['PositionGroup']\nsns.countplot(x=position_group_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Postion Group\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:30.299387Z","iopub.execute_input":"2021-09-20T17:48:30.300178Z","iopub.status.idle":"2021-09-20T17:48:30.571891Z","shell.execute_reply.started":"2021-09-20T17:48:30.300108Z","shell.execute_reply":"2021-09-20T17:48:30.570888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The most injuries are sustained by players in the <b> Linebacker (LB)</b> position group during a play followed by those in the <b>Wide Receiver (WR) and Defensive Back (DB)</b> position group.\n\n### Field Type/Surface","metadata":{}},{"cell_type":"code","source":"fig_dims = (8, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nfield_type_count = play_list_df['FieldType']\nsns.countplot(x=field_type_count,palette='viridis')\nplt.title(\"Number of Injury Occurances by Field Type\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:30.996515Z","iopub.execute_input":"2021-09-20T17:48:30.996847Z","iopub.status.idle":"2021-09-20T17:48:31.201536Z","shell.execute_reply.started":"2021-09-20T17:48:30.996811Z","shell.execute_reply":"2021-09-20T17:48:31.200050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are more injuries on <b>Synthetic</b> fields.\n\n#### Field Type/Surface vs. Roster Position","metadata":{}},{"cell_type":"code","source":"fig_dims = (14, 5)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nroster_position_count = play_list_df['RosterPosition']\nsns.countplot(x=roster_position_count, data=play_list_df,palette='viridis',hue='FieldType')\nplt.title(\"Number of Injury Occurances by Roster Postion\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:31.647379Z","iopub.execute_input":"2021-09-20T17:48:31.648275Z","iopub.status.idle":"2021-09-20T17:48:31.965361Z","shell.execute_reply.started":"2021-09-20T17:48:31.648222Z","shell.execute_reply":"2021-09-20T17:48:31.964549Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Natural surfaces result in more injuries for players in the Linebacker, Safety, Defensive Lineman and Offensive Lineman roster positions.\n\nSynthetic surfaces in more injuries for players in the Wide Receiver, Cornerback and Running Back roster positions\n\n<u>Note:</u> The Roster Position refers to the official position assigned to the player but it may vary in the actual play itself. The Position refers to the player's position during the actual play so this information must be verified with the Position data.\n\n#### Field Type/Surface vs. Position","metadata":{}},{"cell_type":"code","source":"fig_dims = (14, 5)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nposition_count = play_list_df['Position']\nsns.countplot(x=position_count,data=play_list_df,palette='viridis',hue='FieldType')\nplt.title(\"Number of Injury Occurances by Postion\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:32.292341Z","iopub.execute_input":"2021-09-20T17:48:32.292644Z","iopub.status.idle":"2021-09-20T17:48:32.685296Z","shell.execute_reply.started":"2021-09-20T17:48:32.292612Z","shell.execute_reply":"2021-09-20T17:48:32.683980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Players in the Wide Receivers (WR) position, who sustain the most injuries during a play, sustain <b>more injuries on Synthetic surfaces than Natural ones.</b>\n- Players in 7 out of 15 positions sustain more injuries on Synthetic Surfaces.\n- Players in 5 out of 15 positions sustain more injuries on Natural Surfaces.\n- Players in 3 out of 15 positions sustain about the same injuries on both surfaces.\n\n#### Field Type/Surface vs. Position Group","metadata":{}},{"cell_type":"code","source":"fig_dims = (14, 5)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nposition_group_count = play_list_df['PositionGroup']\nsns.countplot(x=position_group_count, data=play_list_df,palette='viridis',hue='FieldType')\nplt.title(\"Number of Injury Occurances by Postion Group\", fontsize=15)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:33.592036Z","iopub.execute_input":"2021-09-20T17:48:33.592431Z","iopub.status.idle":"2021-09-20T17:48:33.900155Z","shell.execute_reply.started":"2021-09-20T17:48:33.592394Z","shell.execute_reply":"2021-09-20T17:48:33.899275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Players in the Linebacker (LB) position group, who sustain the most injuries during a play, sustain <b>more injuries on Natural surfaces than Synthetic ones.</b>\n- Players in 3 out of 7 position groups sustain more injuries on Synthetic Surfaces.\n- Players in 3 out of 7 position groups sustain more injuries on Natural Surfaces.\n- Players in 1 out of 7 position groups sustain about the same injuries on both surfaces.\n\n#### Field Type/Surface vs. Stadium Type","metadata":{}},{"cell_type":"code","source":"fig_dims = (8, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nstadium_type_count = play_list_df['StadiumType']\nsns.countplot(x=stadium_type_count, data=play_list_df,palette='viridis',hue='FieldType')\nplt.title(\"Number of Injury Occurances by Stadium Type\", fontsize=15)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:35.046644Z","iopub.execute_input":"2021-09-20T17:48:35.046999Z","iopub.status.idle":"2021-09-20T17:48:35.309301Z","shell.execute_reply.started":"2021-09-20T17:48:35.046962Z","shell.execute_reply":"2021-09-20T17:48:35.308424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Injuries sustained in outdoor stadiums are primarily because of Natural Surfaces.\n- Injuries sustained in indoor stadiums are primarily because of Synthetic Surfaces.\n\n#### Field Type/Surface vs. Temperature","metadata":{}},{"cell_type":"code","source":"graph = sns.FacetGrid(play_list_df, col=\"FieldType\", height=6)\ngraph.map_dataframe(sns.histplot,x=\"Temperature\",binwidth=1)\n\n#Setting the title for the FacetGrid \ngraph.fig.subplots_adjust(top=0.85)\ngraph.fig.suptitle('Number of Injury Occurances by Temperature', fontsize=20)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:35.947087Z","iopub.execute_input":"2021-09-20T17:48:35.947584Z","iopub.status.idle":"2021-09-20T17:48:36.671026Z","shell.execute_reply.started":"2021-09-20T17:48:35.947551Z","shell.execute_reply":"2021-09-20T17:48:36.670334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- There is a rise in injuries on Synthetic surfaces between 67-71 degrees, with the most injuries occurring between 67-68 degrees.\n- Injuries spike at a few different temperatures for Natural surfaces, with the most injuries occurring between 88-89 degrees.\n\n## Player Track Data \n### Identifying Potential Instances of Injury\n\nThe player_track_df DataFrame gives us the most information about how the player's body is moving during a play. \n\n<i>\"Injuries occur during football games and practice due to the combination of high speeds and full contact. While overuse injuries can occur, traumatic injuries such as concussions are most common. The force applied to either bringing an opponent to the ground or resisting being brought to the ground makes football players prone to injury anywhere on their bodies, regardless of protective equipment.\"</i> - Football Injuries, University of Rochester Medical Center \n\nSource: “Football Injuries.” UR Medicine, University of Rochester Medical Center, University of Rochester Medical Center, 2010, www.urmc.rochester.edu/orthopaedics/sports-medicine/football-injuries.cfm. \n\nGiven the context above, it might be possible to identify the moment of injury by tracking the instant when the maximum change occurs in all the variables associated with movement. \n\nWe will create a new DataFrame with variables that reflect the player's motion during the play. \n\n- delta_dir: Change in angle of player motion\n- delta_o: Change in player orientation\n- delta_s: Change in player speed\n\nNote: \n- x and y capture the location of the player on the field and they are not as important in identifying when the injury occured.\n- dis captures the distance travelled and s captures the speed which is the distance travelled over the time difference so there is no need to include both variables. ","metadata":{}},{"cell_type":"code","source":"# Creating a new DataFrame to the change in variables\ndelta_player_track_df = player_track_df['PlayKey'].to_frame()\n\ndelta_player_track_df['time'] = player_track_df['time']\n\n#Adding new columns to reflect the absolute change in variables using DataFrame.diff()\n#np.where ensures that in case the time is 0.0 the difference is not calculated as this indicates the row is associated with the next PlayKey. In that case the value will be set to 0\n#np.where(condition,value if condition is true, value if condition is false)\n\ndelta_player_track_df['delta_dir'] = np.where(player_track_df['time'] == 0, 0, abs(player_track_df['dir'].diff()))\ndelta_player_track_df['delta_o'] = np.where(player_track_df['time'] == 0, 0, abs(player_track_df['o'].diff()))\ndelta_player_track_df['delta_s'] = np.where(player_track_df['time'] == 0, 0, abs(player_track_df['s'].diff()))     ","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:37.150089Z","iopub.execute_input":"2021-09-20T17:48:37.150515Z","iopub.status.idle":"2021-09-20T17:48:37.165303Z","shell.execute_reply.started":"2021-09-20T17:48:37.150483Z","shell.execute_reply":"2021-09-20T17:48:37.164261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Checking number of rows\ndelta_player_track_df.shape[0]","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:38.079856Z","iopub.execute_input":"2021-09-20T17:48:38.080178Z","iopub.status.idle":"2021-09-20T17:48:38.086347Z","shell.execute_reply.started":"2021-09-20T17:48:38.080147Z","shell.execute_reply":"2021-09-20T17:48:38.085544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now that we have a DataFrame containing all the necessary variables, we can determine which values are outside the norm for each one of these variables. \n\nWe are assuming that the injury is sustained as a result of impact, which would be reflected as a sudden change in players normal motion. We will assume any instance where the player's movements are above average across any of these variables indicates a <b>high risk instance</b> where the injury could have occured.  \n\nIf we assume the data has a gaussian distribution (as the majority of the player's motion does not result in injury), we can calculate the z score for each variable to determine which values are outliers. \n\n- A z-score tells us how many standard deviations away a value is from the mean. \n- Outliers will be values that are more than 3 standard deviations away from the average.\n- The outliers will be potential instances where the player may have sustained the injury.","metadata":{}},{"cell_type":"code","source":"#Calculating z-scores for dataset as a whole\nfrom scipy import stats\nfrom scipy.stats import zscore\n\nz_score_dir = stats.zscore(delta_player_track_df['delta_dir'])\nz_score_o = stats.zscore(delta_player_track_df['delta_o'])\nz_score_s = stats.zscore(delta_player_track_df['delta_s'])","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:40.076758Z","iopub.execute_input":"2021-09-20T17:48:40.077755Z","iopub.status.idle":"2021-09-20T17:48:40.088315Z","shell.execute_reply.started":"2021-09-20T17:48:40.077702Z","shell.execute_reply":"2021-09-20T17:48:40.087278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Distribution of Data\n### Change in Angle of Player Motion","metadata":{}},{"cell_type":"code","source":"fig_dims = (12, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nhighlight = delta_player_track_df[z_score_dir>3]\n\nax.scatter(y='delta_dir',x='time', data=delta_player_track_df)\nax.scatter(y='delta_dir',x='time', data=highlight,facecolor=\"red\")\nax.set_xlabel(\"Time (s)\")\nax.set_ylabel(\"Change in Angle (Degrees)\")\nax.set_title(\"Change in Angle of Player Motion vs. Time\",fontsize=20)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:42.363603Z","iopub.execute_input":"2021-09-20T17:48:42.364375Z","iopub.status.idle":"2021-09-20T17:48:42.711473Z","shell.execute_reply.started":"2021-09-20T17:48:42.364327Z","shell.execute_reply":"2021-09-20T17:48:42.710382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<b>Highlighted points have a z-score > 3</b>\n\nThe majority of plays seem to require some type of instantaneous change in the player's direction of motion in the first 40 seconds of the game. \n- This could be attributed to execution of plays which requires rapid movement and coordination with other players.\n- It also suggests that the risk of injury is the greatest in the first 40 seconds of the game. \n\n### Change in Player Orientation","metadata":{}},{"cell_type":"code","source":"fig_dims = (12, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nhighlight = delta_player_track_df[z_score_o>3]\n\nax.scatter(y='delta_o',x='time', data=delta_player_track_df)\nax.scatter(y='delta_o',x='time', data=highlight,facecolor=\"red\")\nax.set_xlabel(\"Time (s)\")\nax.set_ylabel(\"Change in Orientation (Degrees)\")\nax.set_title(\"Change in Player Orientation vs. Time\",fontsize=20)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:44.556547Z","iopub.execute_input":"2021-09-20T17:48:44.556903Z","iopub.status.idle":"2021-09-20T17:48:44.899335Z","shell.execute_reply.started":"2021-09-20T17:48:44.556865Z","shell.execute_reply":"2021-09-20T17:48:44.898482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<b>Highlighted points have a z-score > 3</b>\n\nCorrelating with the Change in Angle, the majority of plays seem to require some type of instantaneous change in the direction the player is facing in the first 40 seconds of the game. \n- The correlation makes sense as the player would orient themselves in a certain direction and begin/change angle of motion simultaneously during a play.  \n- Again, it also suggests that the risk of injury is the greatest in the first 40 seconds of the game. \n\n### Change in Player Speed","metadata":{}},{"cell_type":"code","source":"fig_dims = (12, 4)\nfig, ax = plt.subplots(figsize=fig_dims)\n\nhighlight = delta_player_track_df[z_score_s>3]\n\nax.scatter(y='delta_s',x='time', data=delta_player_track_df)\nax.scatter(y='delta_s',x='time', data=highlight,facecolor=\"red\")\nax.set_xlabel(\"Time (s)\")\nax.set_ylabel(\"Change in Speed (Yards per Second)\")\nax.set_title(\"Change in Player Speed vs. Time\",fontsize=20)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:46.566348Z","iopub.execute_input":"2021-09-20T17:48:46.567166Z","iopub.status.idle":"2021-09-20T17:48:46.909566Z","shell.execute_reply.started":"2021-09-20T17:48:46.567116Z","shell.execute_reply":"2021-09-20T17:48:46.908605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<b>Highlighted points have a z-score > 3</b>\n\nGenerally the change in speed values are clustered closer together, indicating that the variation in speed is somewhat lower for most of these plays. \n- Rapid changes in speed are associated with potential instances of injury, which makes sense as these could indicate impact\n\n### Key Takeaways from Visualizing Distributions\nNone of the variables follow a gaussian distribution, however, the variables do seem to cluster below certain values. which can be helpful in visually identifying outliers. \n\nIdentifying points with a z-score > 3 does a somewhat decent job of identifying outliers so we will proceed with this method. However, we will calculate the z-scores for the variables for each PlayKey instead of the data as whole to improve the accuracy a bit. \n\n## Identifying High Risk Potential Instances of Injury\n","metadata":{}},{"cell_type":"code","source":"#Creating a DataFrame to store all the high risk instances\nhigh_risk_playkey = pd.DataFrame(columns = ['PlayKey','time','delta_dir','delta_o','delta_s'])\n\n#Creating a groupby object so we can retrive the keys which in this case are the PlayKeys\ngroups = delta_player_track_df.groupby('PlayKey')\n\n# extract keys from groups\nkeys = groups.groups.keys()\n\n#Creating a for loop that will calculate the z-scores for each individual PlayKey and check if any of the values are more than three standard deviations away\nfor i in keys: \n    #Creating a Dataframe with the desired rows for each Playkey\n    i_df = delta_player_track_df[delta_player_track_df['PlayKey']==i]\n    \n    #Calculate z-scores for this PlayKey\n    z_score_dir = stats.zscore(i_df['delta_dir'])\n    z_score_o = stats.zscore(i_df['delta_o'])\n    z_score_s = stats.zscore(i_df['delta_s'])\n    \n    #Filter by z-scores exceeding 3\n    i_df = i_df[(z_score_dir>3) | (z_score_o>3) | (z_score_s>3)]\n    \n    #Attaching the DataFrame to the high_risk_playkey DataFrame \n    high_risk_playkey = pd.concat([high_risk_playkey, i_df], axis=0)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:48.638936Z","iopub.execute_input":"2021-09-20T17:48:48.639452Z","iopub.status.idle":"2021-09-20T17:48:49.381377Z","shell.execute_reply.started":"2021-09-20T17:48:48.639405Z","shell.execute_reply":"2021-09-20T17:48:49.380728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"high_risk_playkey.shape[0]","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:49.997586Z","iopub.execute_input":"2021-09-20T17:48:49.998518Z","iopub.status.idle":"2021-09-20T17:48:50.004938Z","shell.execute_reply.started":"2021-09-20T17:48:49.998475Z","shell.execute_reply":"2021-09-20T17:48:50.004180Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Checking if the DataFrame contains all the PlayKey values\nlen(pd.unique(high_risk_playkey['PlayKey']))","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:50.817240Z","iopub.execute_input":"2021-09-20T17:48:50.817592Z","iopub.status.idle":"2021-09-20T17:48:50.824266Z","shell.execute_reply.started":"2021-09-20T17:48:50.817557Z","shell.execute_reply":"2021-09-20T17:48:50.823357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We now have a DataFrame with all the high risk instances for all PlayKey values. Although there are still a significant number of instances for each PlayKey we have narrowed down the values from our original data. \n\nThis allows us to answer the following questions:\n\n- On average, when does a potential instance of injury occur during a play for each type of surface?\n- How many potential instances of injury occur during a play for each type of surface?\n\nNote:\n- One or more instances in each play could represent when the injury occured (Example, multiple tackles resulting in a knee injury.). \n- The other instances could be a result of regular in-game moves that require instantaneous movement.","metadata":{}},{"cell_type":"code","source":"#Creating a new DataFrame with the PlayKeys and associated surface/field type\nsurfaces = play_list_df[['PlayKey','FieldType']]\n#Merging the two DataFrames to add the surface/field type values\nhigh_risk_playkey = pd.merge(left=high_risk_playkey, right=surfaces, left_on='PlayKey', right_on='PlayKey')","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:48:53.036903Z","iopub.execute_input":"2021-09-20T17:48:53.037233Z","iopub.status.idle":"2021-09-20T17:48:53.057269Z","shell.execute_reply.started":"2021-09-20T17:48:53.037204Z","shell.execute_reply":"2021-09-20T17:48:53.056392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"surface_risk = high_risk_playkey.groupby('FieldType').agg(number_of_instances=('FieldType',pd.Series.value_counts),min_time=('time',np.min),max_time=('time',np.max),avg_time=('time',np.mean))\nsurface_risk.round(1)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-09-20T17:48:53.580969Z","iopub.execute_input":"2021-09-20T17:48:53.581250Z","iopub.status.idle":"2021-09-20T17:48:53.609739Z","shell.execute_reply.started":"2021-09-20T17:48:53.581221Z","shell.execute_reply":"2021-09-20T17:48:53.608922Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- There are 18.72% more instances of potential injury during plays on Synthetic surfaces as opposed to Natural surfaces.\n- The average time for a potential instance of injury to occur is slightly lower on natural surfaces as opposed to Synthetic.","metadata":{}},{"cell_type":"markdown","source":"# Summary of Data Analysis\n\nOverall, Synthetic surfaces result in <b>13.89%</b> more injuries than Natural surfaces\n- Knee and Ankle injuries have the highest occurrences.\n- The majority of injuries result in players missing between 1 day or more or 7 days or more.\n\n### Days Missed\nInjuries on synthetic surfaces result in players missing more days than those on natural surfaces. \n- Players have a relatively higher likelihood of suffering medium duration injuries on Natural surfaces.\n- Players have a relatively higher likelihood of suffering short, long and indefinite duration injuries on Synthetic surfaces. \n\n\n### Roster Position\n- Natural surfaces result in more injuries for players in the Linebacker, Safety, Defensive Lineman and Offensive Lineman roster positions.\n- Synthetic surfaces in more injuries for players in the Wide Receiver, Cornerback and Running Back roster positions\n\n<u>Note:</u> The Roster Position refers to the official position assigned to the player but it may vary in the actual play itself. The Position refers to the player's position during the actual play so this information must be verified with the Position data.\n\n### Position\nPlayers in the Linebacker (LB) position group, who sustain the most injuries during a play, sustain <b>more injuries on Natural surfaces than Synthetic ones.</b>\n- Players in 3 out of 7 position groups sustain more injuries on Synthetic Surfaces.\n- Players in 3 out of 7 position groups sustain more injuries on Natural Surfaces.\n- Players in 1 out of 7 position groups sustain about the same injuries on both surfaces.\n\n### Position Group\nPlayers in the Linebacker (LB) position group, who sustain the most injuries during a play, sustain <b>more injuries on Natural surfaces than Synthetic ones.</b>\n- Players in 3 out of 7 position groups sustain more injuries on Synthetic Surfaces.\n- Players in 3 out of 7 position groups sustain more injuries on Natural Surfaces.\n- Players in 1 out of 7 position groups sustain about the same injuries on both surfaces.\n\n### Stadium Type\n- Injuries sustained in outdoor stadiums are primarily because of Natural Surfaces.\n- Injuries sustained in indoor stadiums are primarily because of Synthetic Surfaces.\n\n## Identifying Potential Instances of Injury\n\nWe are assuming that the injury is sustained as a result of impact, which would be reflected as a sudden change in players normal motion. We will assume any instance where the player's movements are out of the ordinary across the variables in the Player Track Data indicates a <b>high risk instance</b> where the injury could have occured.  \n- The majority of plays seem to require some type of instantaneous change in the player's direction of motion and orientation in the first 40 seconds of the game.\n- The risk of injury is also the greatest during these first 40 seconds of the game.\n- Generally the variation in player speed is somewhat lower for most of these plays.\n- There are 18.72% more instances of potential injury during plays on Synthetic surfaces as opposed to Natural surfaces.\n- The average time for a potential instance of injury to occur is slightly lower on natural surfaces as opposed to Synthetic.","metadata":{}}]}