{"cells":[{"metadata":{},"cell_type":"markdown","source":"## NFL Analysis\n\n![](https://techcrunch.com/wp-content/uploads/2015/11/1st-future2.png?w=730&crop=1)\n\n\n### Points to be noted from the Description\n1. No Leaderboard\n2. No Predictive model developing required\n3. In NFL, 12 stadiums have fields with synthetic turfs. It has also been observed that the Lower-limb injuries are greater in Synthetic turf compared to the Natural turf (since Synthetic turf does not release cleats as Natural turf which is leading to the injuries)\n> Lower-limb injury : Synthetic turf > Natural turf\n4. NFL individual player tracking characteristics such as player speed, directional changes, acceleration/ deceleration, distance, etc., have been provided.\n\n### Challenge\n* Yet to be determined, whether player movement patterns and other measures of player performance differ across playing surfaces and how they contribute to injury.\n* Examining effects of playing on Synthetic vs Natural turf can have on player movements leading to injuries.\n* Characterize differences in player movement between surfaces and identify specific scenarios such as Field surface, Weather, Position, Play type, etc to prevent injury or influence player movement.\n\n\nIn this challenge, you're tasked to investigate the relationship between the playing surface and the injury and performance of National Football League (NFL) athletes and to examine factors that may contribute to lower extremity injuries and to prevent them.\n"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Importing the required packages\n\nimport numpy as np \nimport pandas as pd \n\n# Visualization\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nsns.set(style=\"whitegrid\")\nimport plotly.express as px\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### **About the data**:\nThere are three files provided in the dataset, as described below:\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 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 play 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":"markdown","source":"### Loading the data"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Read the input files\nplay = pd.read_csv('../input/nfl-playing-surface-analytics/PlayList.csv')\ninjury = pd.read_csv('../input/nfl-playing-surface-analytics/InjuryRecord.csv')\nplayer = pd.read_csv('../input/nfl-playing-surface-analytics/PlayerTrackData.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data Exploration"},{"metadata":{"trusted":true},"cell_type":"code","source":"play.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"injury.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Player data analysis\n\n### 1. General information"},{"metadata":{"trusted":true},"cell_type":"code","source":"unique_players = play.PlayerKey.nunique()\nunique_games = play.GameID.nunique()\nunique_plays = play.PlayKey.nunique()\n\nprint('There are {} players in the dataset.'.format(unique_players))\nprint('There are {} games in the dataset.'.format(unique_games))\nprint('There are {} plays in the dataset.'.format(unique_plays))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 2. Game information"},{"metadata":{"trusted":true},"cell_type":"code","source":"play.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create a dataframe with game-level information\ngame = play[['GameID', 'StadiumType', 'FieldType', 'Weather', 'Temperature']].drop_duplicates().reset_index().drop(columns=['index'])\ngame.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"a = play[['PlayKey','PlayType']].drop_duplicates().groupby('PlayType').count()['PlayKey'].sort_values()\na = pd.DataFrame({'PlayType':a.index, 'Count':a.values}).sort_values(by='Count',ascending=False)\na","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ax = sns.barplot(x=\"Count\",y=\"PlayType\", data = a)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Exploring the Game-level information\n* Information like RosterPosition, StadiumType, FieldType, Temperature, Weather, PlayType, PlayerGamePlay"},{"metadata":{"trusted":true},"cell_type":"code","source":"play.RosterPosition.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play.StadiumType.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play.FieldType.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play.Temperature.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play.Weather.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play.PlayType.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def add_value_labels(ax, spacing=5):\n    # For each bar: Place a label\n    for rect in ax.patches:\n        # Get X and Y placement of label from rect.\n        y_value = rect.get_height()\n        x_value = rect.get_x() + rect.get_width() / 2\n\n        # Number of points between bar and label. Change to your liking.\n        space = spacing\n        # Vertical alignment for positive values\n        va = 'bottom'\n\n        # If value of bar is negative: Place label below bar\n        if y_value < 0:\n            # Invert space to place label below\n            space *= -1\n            # Vertically align label at top\n            va = 'top'\n\n        # Use Y value as label and format number with one decimal place\n        label = \"{:.0f}\".format(y_value)\n\n        # Create annotation\n        ax.annotate(\n            label,                      # Use `label` as label\n            (x_value, y_value),         # Place label at end of the bar\n            xytext=(0, space),          # Vertically shift label by `space`\n            textcoords=\"offset points\", # Interpret `xytext` as offset in points\n            ha='center',                # Horizontally center label\n            va=va)                      # Vertically align label differently for\n                                        # positive and negative values.\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def visualize_game_features(play, rotation = 90, add_labels = False, figsize=(10,10)):\n    #fig, axs = plt.subplots(ncols=2,nrows=3)\n    plt.style.use('ggplot')\n    fig = plt.figure(figsize=figsize)\n    grid = plt.GridSpec(4, 3, hspace=0.5, wspace=0.5)\n    roster_ax = fig.add_subplot(grid[1,0:])\n    stadium_ax = fig.add_subplot(grid[2,:2])\n    fieldtype_ax = fig.add_subplot(grid[2,2])\n    weather_ax = fig.add_subplot(grid[3,1])\n    #temperature_ax = fig.add_subplot(grid[2, 0:])\n    #temperature_box_ax = fig.ad d_subplot(grid[3, 0:])\n\n    roster_ax.bar(play.RosterPosition.value_counts().keys(), play.RosterPosition.value_counts().values,color='#00c2c7')\n    roster_ax.set_title('RosterPosition')\n    roster_ax.set_xticklabels(play.RosterPosition.value_counts().keys(),rotation=25)\n    \n    if add_labels:\n        add_value_labels(roster_ax, spacing=5)\n    \n    stadium_ax.bar(play.StadiumType.value_counts().keys(), play.StadiumType.value_counts().values, color='#00c2c7')\n    stadium_ax.set_title('StadiumType')\n    stadium_ax.set_xticklabels(play.StadiumType.value_counts().keys(), rotation=rotation)\n    \n    if add_labels:\n        add_value_labels(stadium_ax, spacing=5)\n\n    fieldtype_ax.bar(play.FieldType.value_counts().keys(), play.FieldType.value_counts().values, color=['#00c2c7', '#ff9e15'])\n    fieldtype_ax.set_title('FieldType')\n    fieldtype_ax.set_xticklabels(play.FieldType.value_counts().keys(), rotation=0)\n    \n    if add_labels:\n        add_value_labels(fieldtype_ax, spacing=5)\n\n    weather_ax.bar(play.Weather.value_counts().keys(), play.Weather.value_counts().values, color='#00c2c7')\n    weather_ax.set_title('Weather')\n    weather_ax.set_xticklabels(play.Weather.value_counts().keys(), rotation=rotation)\n    \n    if add_labels:\n        add_value_labels(weather_ax, spacing=5)\n        \n    temperature_ax.hist(play.Temperature.astype(int).values, bins=30, range=(0,90))\n    temperature_ax.set_xlim(0,110)\n    temperature_ax.set_xticks(range(0,110,10))\n    temperature_ax.set_xticklabels(range(0,110,10))\n    temperature_ax.set_title('Temperature')\n    \n    temperature_box_ax.boxplot(play.Temperature.astype(int).values, vert=False)\n    temperature_box_ax.set_xlim(0,110)\n    temperature_box_ax.set_xticks(range(0,110,10))\n    temperature_box_ax.set_xticklabels(range(0,110,10))\n    temperature_box_ax.set_yticklabels(['Temperature'])\n\n    plt.suptitle('Game-Level Exploration', fontsize=16)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def clean_weather(row):\n    cloudy = ['Cloudy 50% change of rain', 'Hazy', 'Cloudy.', 'Overcast', 'Mostly Cloudy',\n          'Cloudy, fog started developing in 2nd quarter', 'Partly Cloudy',\n          'Mostly cloudy', 'Rain Chance 40%',' Partly cloudy', 'Party Cloudy',\n          'Rain likely, temps in low 40s', 'Partly Clouidy', 'Cloudy, 50% change of rain','Mostly Coudy', '10% Chance of Rain',\n          'Cloudy, chance of rain', '30% Chance of Rain', 'Cloudy, light snow accumulating 1-3\"',\n          'cloudy', 'Coudy', 'Cloudy with periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph.',\n         'Cloudy fog started developing in 2nd quarter', 'Cloudy light snow accumulating 1-3\"',\n         'Cloudywith periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph.',\n         'Cloudy 50% change of rain', 'Cloudy and cold',\n       'Cloudy and Cool', 'Partly cloudy']\n    \n    clear = ['Clear, Windy',' Clear to Cloudy', 'Clear, highs to upper 80s',\n             'Clear and clear','Partly sunny',\n             'Clear, Windy', 'Clear skies', 'Sunny', 'Partly Sunny', 'Mostly Sunny', 'Clear Skies',\n             'Sunny Skies', 'Partly clear', 'Fair', 'Sunny, highs to upper 80s', 'Sun & clouds', 'Mostly sunny','Sunny, Windy',\n             'Mostly Sunny Skies', 'Clear and Sunny', 'Clear and sunny','Clear to Partly Cloudy', 'Clear Skies',\n            'Clear and cold', 'Clear and warm', 'Clear and Cool', 'Sunny and cold', 'Sunny and warm', 'Sunny and clear']\n    \n    rainy = ['Rainy', 'Scattered Showers', 'Showers', 'Cloudy Rain', 'Light Rain', 'Rain shower', 'Rain likely, temps in low 40s.', 'Cloudy, Rain']\n    \n    snow = ['Heavy lake effect snow']\n    \n    indoor = ['Controlled Climate', 'Indoors', 'N/A Indoor', 'N/A (Indoors)']\n        \n    if row.Weather in cloudy:\n        return 'Cloudy'\n    \n    if row.Weather in indoor:\n        return 'Indoor'\n    \n    if row.Weather in clear:\n        return 'Clear'\n    \n    if row.Weather in rainy:\n        return 'Rain'\n    \n    if row.Weather in snow:\n        return 'Snow'\n      \n    if row.Weather in ['Cloudy.', 'Heat Index 95', 'Cold']:\n        return np.nan\n    \n    return row.Weather\n\ndef clean_stadiumtype(row):\n    if row.StadiumType in ['Bowl', 'Heinz Field', 'Cloudy']:\n        return np.nan\n    else:\n        return row.StadiumType\n\ndef clean_play_df(play_df):\n    play_df_cleaned = play_df.copy()\n    \n    # clean StadiumType\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Oudoor|Outdoors|Ourdoor|Outddors|Outdor|Outside', 'Outdoor')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Indoors|Indoor, Roof Closed|Indoor, Open Roof', 'Indoor')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Closed Dome|Domed, closed|Domed, Open|Domed, open|Dome, closed|Domed', 'Dome')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Retr. Roof-Closed|Outdoor Retr Roof-Open|Retr. Roof - Closed|Retr. Roof-Open|Retr. Roof - Open|Retr. Roof Closed', 'Retractable Roof')\n    play_df_cleaned['StadiumType'] = play_df_cleaned.apply(lambda row: clean_stadiumtype(row), axis=1)\n    \n    # clean Weather\n    play_df_cleaned['Weather'] = play_df_cleaned.apply(lambda row: clean_weather(row), axis=1)\n    \n    return play_df_cleaned","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play_df_cleaned = clean_play_df(play)\ngame_df_cleaned = play_df_cleaned[['GameID', 'StadiumType', 'FieldType', 'Weather', 'Temperature','RosterPosition']].drop_duplicates().reset_index().drop(columns=['index'])\nvisualize_game_features(game_df_cleaned, rotation=45, add_labels = True, figsize=(12,16))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"Injury Data\nFirst lets look at the injury data. It's a fairly small file with only 105 injury plays shown. I notice that many of the rows for the injury plays do not show PlayerKey, GameId, etc. I'm not sure if this is a bug or intentially done.\n\nPlayerKey, GameId, PlayKey\nBodyPart\nSurface\nDM_M1, DM_M7, DM_28, DM_42 - One hot encoding the number of days missed for injury"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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}