{"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":"# Welcome to the [NFL Big Data Bowl 2022](https://www.kaggle.com/c/nfl-big-data-bowl-2022)!\n\n<center><img src='https://www.stadiumsofprofootball.com/wp-content/uploads/2016/07/metlifegiants2012955.jpg' width='600' height=\"600\" ></center>\n\n#### This notebook will go through an extensive analysis to view and explore the NFL Big Data Bowl 2022 competition data , this note bote (for now) will be focusing on 2018 data to explore the plays data and players movements, to that end we will be creating functions to easilty plot players movments\n<h4><font color='darkred'>Please note that this work you're about to see here is a work in progress so a lot will be added later</font></h4>\n\n\n## The notebook will have the following sections:\n ### - [Data Imports and initial exploring](#load_data).\n ####  you can skip this part of you are familiar with the competition data.\n ### - [Exploratory data analysis](#EDA).\n ### - [Player movement analysis](#PMEDA).\n ### - [ML starter](#ml).\n ####  this part will contain the whole EDA process to explore all the datasets.\n#### P.S.  There won't be a dedicated parts for cleaning or features engineering as few of both will be done along the way since the data is pretty much preprocessed.","metadata":{}},{"cell_type":"markdown","source":"### First we import libraries to work with","metadata":{}},{"cell_type":"code","source":"# imports\nimport gc\nimport os\nimport sys\nfrom io import BytesIO\nimport time\nfrom IPython.display import Image, display as image, display\nfrom IPython.display import HTML\nimport requests\nfrom PIL import Image\nimport numpy as np\nimport statistics as st\nimport datetime\nfrom matplotlib.ticker import (MultipleLocator, AutoMinorLocator)\nfrom matplotlib import rc\nimport pandas as pd\nimport dask.dataframe as dd\npd.set_option('display.max_columns', 50)\npd.set_option('display.max_rows',120)\nimport matplotlib.pyplot as plt\nimport matplotlib.animation\nimport matplotlib.gridspec as gridspec\nimport seaborn as sns\nfrom termcolor import colored\n%matplotlib inline\nsns.set_style('darkgrid')\nimport plotly.express as px\nimport plotly.figure_factory as ff\nhcmap = sns.blend_palette(['yellowgreen','orange','orangered','red'],n_colors=12,as_cmap=True)\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\nimport warnings\nwarnings.filterwarnings('ignore')\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.neural_network import MLPClassifier\nfrom sklearn.naive_bayes import GaussianNB\nfrom sklearn.neighbors import KNeighborsClassifier\nfrom sklearn.tree import DecisionTreeClassifier\nfrom sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier\n# from sklearn.compose import ColumnTransformer\n# from sklearn.pipeline import Pipeline\n# from sklearn.impute import SimpleImputer\n# from sklearn.feature_selection import mutual_info_regression\n# from sklearn.preprocessing import OneHotEncoder, StandardScaler, OrdinalEncoder\nfrom sklearn.model_selection import train_test_split as split\n# from sklearn.cluster import KMeans\n# from sklearn.decomposition import PCA\n# from sklearn.cluster import KMeans \nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.model_selection import GridSearchCV as Grid\nimport xgboost as xgb\nfrom sklearn.metrics import (f1_score, accuracy_score, balanced_accuracy_score, precision_score, recall_score, roc_auc_score, confusion_matrix)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-01-07T09:14:02.299014Z","iopub.execute_input":"2022-01-07T09:14:02.299425Z","iopub.status.idle":"2022-01-07T09:14:06.117291Z","shell.execute_reply.started":"2022-01-07T09:14:02.299323Z","shell.execute_reply":"2022-01-07T09:14:06.116272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='load_data'></a>\n# Loading Data and exploring main statistics\n\n### This part will be dedicated to data imports and also initial exploring of the datasets.","metadata":{}},{"cell_type":"code","source":"input_data_path = []\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        input_data_path.append(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:14:06.11952Z","iopub.execute_input":"2022-01-07T09:14:06.120324Z","iopub.status.idle":"2022-01-07T09:14:06.138038Z","shell.execute_reply.started":"2022-01-07T09:14:06.120278Z","shell.execute_reply":"2022-01-07T09:14:06.137156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"input_data_path","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:14:06.139322Z","iopub.execute_input":"2022-01-07T09:14:06.139553Z","iopub.status.idle":"2022-01-07T09:14:06.14769Z","shell.execute_reply.started":"2022-01-07T09:14:06.139527Z","shell.execute_reply":"2022-01-07T09:14:06.14715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"games = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/games.csv')\nplays = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/plays.csv')\nplayers = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/players.csv')\ntracking2018 = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/tracking2018.csv',parse_dates=True)\ntracking2019 = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/tracking2019.csv',parse_dates=True)\ntracking2020 = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/tracking2020.csv',parse_dates=True)\nPFFScoutingData = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/PFFScoutingData.csv')\ntemperature = pd.read_csv('/kaggle/input/nfl-temp/temptreture.csv')","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:14:06.14868Z","iopub.execute_input":"2022-01-07T09:14:06.149432Z","iopub.status.idle":"2022-01-07T09:15:50.35414Z","shell.execute_reply.started":"2022-01-07T09:14:06.149397Z","shell.execute_reply":"2022-01-07T09:15:50.352812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center><h2> Now let the analysis begins</h2></center>\n\n\n<center><img src=\"https://www.reactiongifs.us/wp-content/uploads/2018/11/2018-NFL-Football.gif\" width='600' height=\"600\"></center>\n\n","metadata":{}},{"cell_type":"markdown","source":"### Checking tracking datasets","metadata":{}},{"cell_type":"code","source":"tracking2018.head(2)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:15:50.357447Z","iopub.execute_input":"2022-01-07T09:15:50.357698Z","iopub.status.idle":"2022-01-07T09:15:50.392643Z","shell.execute_reply.started":"2022-01-07T09:15:50.357668Z","shell.execute_reply":"2022-01-07T09:15:50.392105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Checking if all columns across all year datasets all equal","metadata":{}},{"cell_type":"code","source":"list(tracking2018.columns) == list(tracking2019.columns) == list(tracking2020.columns)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:15:50.39345Z","iopub.execute_input":"2022-01-07T09:15:50.394162Z","iopub.status.idle":"2022-01-07T09:15:50.398865Z","shell.execute_reply.started":"2022-01-07T09:15:50.394125Z","shell.execute_reply":"2022-01-07T09:15:50.398366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center><img src='https://c.tenor.com/W36eIGSnVakAAAAC/dragons-den-very-good.gif'></center>","metadata":{}},{"cell_type":"markdown","source":"### Getting values with null nflId's","metadata":{}},{"cell_type":"code","source":"tracking2018[tracking2018.nflId.isna()].sample(5)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:15:50.399676Z","iopub.execute_input":"2022-01-07T09:15:50.400151Z","iopub.status.idle":"2022-01-07T09:15:50.684365Z","shell.execute_reply.started":"2022-01-07T09:15:50.400119Z","shell.execute_reply":"2022-01-07T09:15:50.683463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking2018[tracking2018.nflId.isna()].displayName.unique()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:15:50.685797Z","iopub.execute_input":"2022-01-07T09:15:50.686126Z","iopub.status.idle":"2022-01-07T09:15:50.814718Z","shell.execute_reply.started":"2022-01-07T09:15:50.686053Z","shell.execute_reply":"2022-01-07T09:15:50.8138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### Seems like all null values are associated with the ball 🏈 tracking","metadata":{}},{"cell_type":"markdown","source":"### Separating ball tracking from players tracking data","metadata":{}},{"cell_type":"code","source":"ball_18_df = tracking2018[tracking2018.team == 'football'].copy()\ntracking2018 = tracking2018[tracking2018.team != 'football'].copy()\n\nball_19_df = tracking2019[tracking2019.team == 'football'].copy()\ntracking2019 = tracking2019[tracking2019.team != 'football'].copy()\n\nball_20_df = tracking2020[tracking2020.team == 'football'].copy()\ntracking2020 = tracking2020[tracking2020.team != 'football'].copy()\n\nball_18_df.drop(columns=['o', 'dir', 'nflId', 'displayName', 'jerseyNumber', 'position'],inplace=True)\nball_19_df.drop(columns=['o', 'dir', 'nflId', 'displayName', 'jerseyNumber', 'position'],inplace=True)\nball_20_df.drop(columns=['o', 'dir', 'nflId', 'displayName', 'jerseyNumber', 'position'],inplace=True)\ngc.collect()\n\nball_20_df.sample(4)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:15:50.816144Z","iopub.execute_input":"2022-01-07T09:15:50.816463Z","iopub.status.idle":"2022-01-07T09:16:06.494125Z","shell.execute_reply.started":"2022-01-07T09:15:50.816427Z","shell.execute_reply":"2022-01-07T09:16:06.493297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Editing some data types to save memory","metadata":{}},{"cell_type":"code","source":"Dtypes = {'time':'datetime64[ns]', 'x':'float32', 'y':'float32', 's':'float32', 'a':'float32',\n          'dis':'float32', 'o':'float32', 'dir':'float64','event':'object' , 'nflId':'uint16',\n          'displayName':'object', 'jerseyNumber':'uint8', 'position':'object', 'team':'object',\n          'frameId':'int32', 'gameId':'uint32', 'playId':'int16'}\n\nball_dtypes = {'time':'datetime64[ns]', 'x':'float32', 'y':'float32', 's':'float32', 'a':'float32',\n               'dis':'float32','event':'object' ,'frameId':'int32','gameId':'uint32','playId':'int16'}","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:06.495402Z","iopub.execute_input":"2022-01-07T09:16:06.495623Z","iopub.status.idle":"2022-01-07T09:16:06.502834Z","shell.execute_reply.started":"2022-01-07T09:16:06.495598Z","shell.execute_reply":"2022-01-07T09:16:06.501972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we will be converting data types to save memory","metadata":{}},{"cell_type":"code","source":"tracking2018 = tracking2018.astype(Dtypes).copy()\ntracking2019 = tracking2019.astype(Dtypes).copy()\ntracking2020 = tracking2020.astype(Dtypes).copy()\n\ntracking2018 = tracking2018.sort_values(by=['time','gameId','playId', 'displayName']).copy()\ntracking2019 = tracking2019.sort_values(by=['time','gameId','playId', 'displayName']).copy()\ntracking2020 = tracking2020.sort_values(by=['time','gameId','playId', 'displayName']).copy()\n\nball_18_df = ball_18_df.astype(ball_dtypes).copy()\nball_19_df = ball_19_df.astype(ball_dtypes).copy()\nball_20_df = ball_20_df.astype(ball_dtypes).copy()\n\nball_18_df = ball_18_df.sort_values(by=['time','gameId', 'playId']).copy()\nball_19_df = ball_19_df.sort_values(by=['time','gameId', 'playId']).copy()\nball_20_df = ball_20_df.sort_values(by=['time','gameId', 'playId']).copy()\n\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:06.504163Z","iopub.execute_input":"2022-01-07T09:16:06.504385Z","iopub.status.idle":"2022-01-07T09:16:47.94666Z","shell.execute_reply.started":"2022-01-07T09:16:06.50436Z","shell.execute_reply":"2022-01-07T09:16:47.94589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Actually using .copy() and the above mentioned data types helpes reducing the memory usage dramatically (down somewhere around 6.2gb), I think this is as good as it gets if you wanted to go with pandas","metadata":{}},{"cell_type":"markdown","source":"### Now we explore `players` DataFrame","metadata":{}},{"cell_type":"code","source":"players.head(3)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:47.947888Z","iopub.execute_input":"2022-01-07T09:16:47.948124Z","iopub.status.idle":"2022-01-07T09:16:47.960547Z","shell.execute_reply.started":"2022-01-07T09:16:47.948086Z","shell.execute_reply":"2022-01-07T09:16:47.959541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting the names of players with missing birth year","metadata":{"execution":{"iopub.status.busy":"2021-11-03T07:26:47.145591Z","iopub.execute_input":"2021-11-03T07:26:47.145892Z","iopub.status.idle":"2021-11-03T07:26:47.151445Z","shell.execute_reply.started":"2021-11-03T07:26:47.145862Z","shell.execute_reply":"2021-11-03T07:26:47.150582Z"}}},{"cell_type":"code","source":"players.birthDate.isna().sum()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:47.961709Z","iopub.execute_input":"2022-01-07T09:16:47.961945Z","iopub.status.idle":"2022-01-07T09:16:47.97344Z","shell.execute_reply.started":"2022-01-07T09:16:47.961918Z","shell.execute_reply":"2022-01-07T09:16:47.972834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"players[players.birthDate.isna()]","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:47.977411Z","iopub.execute_input":"2022-01-07T09:16:47.978153Z","iopub.status.idle":"2022-01-07T09:16:47.995119Z","shell.execute_reply.started":"2022-01-07T09:16:47.97811Z","shell.execute_reply":"2022-01-07T09:16:47.994217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"missin_dates = {'Antoine Brooks':'1997-10-28', 'Bradlee Anae': '1998-10-17', 'Bravvion Roy':'1996-10-18',\n                'Bryce Hall': '1999-08-14', 'Carter Coughlin': '1997-07-21', 'Chris Claybrooks': '1998-07-17',\n                'Derrek Tuszka':'1997-08-17', 'Hunter Niswander': '1994-11-26', 'James Smith-Williams': '1997-07-29',\n                'Jameson Houston': '1996-06-30', 'Kamren Curl': '1999-03-31', 'Keandre Jones': '1997-09-24',\n                'Michael Danna':  '1997-12-4','Raekwon Davis': '1997-06-10', 'Rashard Lawrence': '1998-08-27',\n                'Taylor Russolino':'1989-05-23', 'Trevon Diggs':'1997-09-20'}","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:47.99661Z","iopub.execute_input":"2022-01-07T09:16:47.996903Z","iopub.status.idle":"2022-01-07T09:16:48.002566Z","shell.execute_reply.started":"2022-01-07T09:16:47.996867Z","shell.execute_reply":"2022-01-07T09:16:48.001681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Adding birth dates","metadata":{}},{"cell_type":"code","source":"missing_index = players[players.birthDate.isna()].index\nfor i in missing_index:\n    plyr = players.loc[i,'displayName'] \n    date = missin_dates[plyr]\n    date = datetime.datetime.strptime(date, \"%Y-%m-%d\")\n    players.loc[i, 'birthDate'] = date","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.003567Z","iopub.execute_input":"2022-01-07T09:16:48.004546Z","iopub.status.idle":"2022-01-07T09:16:48.028219Z","shell.execute_reply.started":"2022-01-07T09:16:48.004511Z","shell.execute_reply":"2022-01-07T09:16:48.027183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"players.loc[missing_index,:]","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.029427Z","iopub.execute_input":"2022-01-07T09:16:48.030423Z","iopub.status.idle":"2022-01-07T09:16:48.0528Z","shell.execute_reply.started":"2022-01-07T09:16:48.030394Z","shell.execute_reply":"2022-01-07T09:16:48.051812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we extrac heights of players and convert it to centimeters and also will be extracting age of players","metadata":{}},{"cell_type":"code","source":"players['feets'] = players.height.str.extract(r'^(\\d)\\-').astype(float)\nplayers['inchs'] = players.height.str.extract(r'(^\\d\\d)').astype(float)\nplayers['alsoinchs'] = players.height.str.extract(r'\\-(\\d*)').astype(float)\nplayers.fillna(0,inplace=True)\nplayers['highcm'] = (players['feets'] * 30.48) + (players['inchs'] *2.54) + (players['alsoinchs']*2.54)\nplayers['age'] = 2018 - pd.to_datetime(players.birthDate).dt.year\nplayers.drop(columns=['feets','inchs','alsoinchs'],inplace=True)\ngc.collect()\nplayers.sample(4)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.054715Z","iopub.execute_input":"2022-01-07T09:16:48.055071Z","iopub.status.idle":"2022-01-07T09:16:48.248164Z","shell.execute_reply.started":"2022-01-07T09:16:48.055029Z","shell.execute_reply":"2022-01-07T09:16:48.247388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"players.info()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.249665Z","iopub.execute_input":"2022-01-07T09:16:48.249887Z","iopub.status.idle":"2022-01-07T09:16:48.26586Z","shell.execute_reply.started":"2022-01-07T09:16:48.249864Z","shell.execute_reply":"2022-01-07T09:16:48.265287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Checking dublicated name (it happens!)","metadata":{}},{"cell_type":"code","source":"players[players.displayName.duplicated(keep=False)]","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.26683Z","iopub.execute_input":"2022-01-07T09:16:48.267634Z","iopub.status.idle":"2022-01-07T09:16:48.287454Z","shell.execute_reply.started":"2022-01-07T09:16:48.267567Z","shell.execute_reply":"2022-01-07T09:16:48.286579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Checking if these names related to the previous missing birth dates","metadata":{}},{"cell_type":"code","source":"set(players[players.displayName.duplicated(keep=False)].index).intersection(set(missing_index))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.288969Z","iopub.execute_input":"2022-01-07T09:16:48.28978Z","iopub.status.idle":"2022-01-07T09:16:48.302327Z","shell.execute_reply.started":"2022-01-07T09:16:48.289742Z","shell.execute_reply":"2022-01-07T09:16:48.301504Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting the duplicated names","metadata":{}},{"cell_type":"code","source":"duplicated_names = sorted(list(set(players[players.displayName.duplicated(keep=False)].displayName.values)))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.304755Z","iopub.execute_input":"2022-01-07T09:16:48.305282Z","iopub.status.idle":"2022-01-07T09:16:48.313426Z","shell.execute_reply.started":"2022-01-07T09:16:48.30524Z","shell.execute_reply":"2022-01-07T09:16:48.312767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### checking if all players in tracking are in the players dataset","metadata":{}},{"cell_type":"code","source":"set(tracking2018.displayName.unique()).issubset(set(players.displayName.unique()))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:48.315759Z","iopub.execute_input":"2022-01-07T09:16:48.316026Z","iopub.status.idle":"2022-01-07T09:16:49.106933Z","shell.execute_reply.started":"2022-01-07T09:16:48.316Z","shell.execute_reply":"2022-01-07T09:16:49.106117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"set(tracking2018.displayName.unique()).difference(set(players.displayName.unique()))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:49.108491Z","iopub.execute_input":"2022-01-07T09:16:49.108793Z","iopub.status.idle":"2022-01-07T09:16:49.894252Z","shell.execute_reply.started":"2022-01-07T09:16:49.108759Z","shell.execute_reply":"2022-01-07T09:16:49.893414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting height and weight (manually)","metadata":{}},{"cell_type":"code","source":"missing_players = {'Charles Leno Jr.':[193 ,304],'Chris Herndon':[193 ,253], 'Chris Hubbard':[193, 295 ],\n                   'Dan McCullers':[201,348], 'Danny Vitale':[183, 225], 'David Williams':[191, 294 ],\n                   'DeVante Bausby':[185 , 190 ], 'Domata Peko Sr.':[191, 322 ], \"Donte' Deayon\":[175, 159],\n                   'Foye Oluokun':[188 ,215], 'Jake Martin':[188,242  ], 'Jeff Wilson':[183,213],\n                   'Joe Jones':[183 , 240], 'Joe Noteboom':[196, 260 ], 'Jon Weeks':[178, 242],\n                   'Josh Perkins':[190, 227], \"Julie'n Davenport\":[201, 313], 'KhaDarel Hodge':[188, 205],\n                   'L.P. LaDouceur':[196, 255], 'Lac Edwards':[193, 209], 'Matt McCrane':[175, 165],\n                   'Matthew Ioannidis':[190,310], 'Matthew Slater':[183, 205], 'Mike Badgley':[178, 183],\n                   'Nate Gerry':[188, 230],'Nickell Robey-Coleman':[173, 180], 'Shaq Mason':[185, 310],\n                   'Trent Brown':[203, 380], 'Trent Scott':[196, 320], 'Zeke Turner':[188,214]}","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:49.895556Z","iopub.execute_input":"2022-01-07T09:16:49.895784Z","iopub.status.idle":"2022-01-07T09:16:49.904198Z","shell.execute_reply.started":"2022-01-07T09:16:49.89576Z","shell.execute_reply":"2022-01-07T09:16:49.903206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"games.head(3)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:49.905394Z","iopub.execute_input":"2022-01-07T09:16:49.905695Z","iopub.status.idle":"2022-01-07T09:16:49.928018Z","shell.execute_reply.started":"2022-01-07T09:16:49.90567Z","shell.execute_reply":"2022-01-07T09:16:49.926906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Checking if there is any duplication in gameid in games dataset","metadata":{}},{"cell_type":"code","source":"games.gameId.duplicated().sum()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:49.929179Z","iopub.execute_input":"2022-01-07T09:16:49.929425Z","iopub.status.idle":"2022-01-07T09:16:49.937786Z","shell.execute_reply.started":"2022-01-07T09:16:49.929401Z","shell.execute_reply":"2022-01-07T09:16:49.936926Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Setting games DataFrame index to gameId","metadata":{}},{"cell_type":"code","source":"games.set_index('gameId',inplace=True)\ngames.gameDate = games.gameDate.astype('datetime64[ns]')\ngames.head(8)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:49.939118Z","iopub.execute_input":"2022-01-07T09:16:49.939501Z","iopub.status.idle":"2022-01-07T09:16:49.958704Z","shell.execute_reply.started":"2022-01-07T09:16:49.939462Z","shell.execute_reply":"2022-01-07T09:16:49.95817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Checking if all games in tracking DataFrame are included in the games DataFrame","metadata":{}},{"cell_type":"code","source":"set(tracking2018.gameId).issubset(set(games.index))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:49.959719Z","iopub.execute_input":"2022-01-07T09:16:49.960023Z","iopub.status.idle":"2022-01-07T09:16:51.300515Z","shell.execute_reply.started":"2022-01-07T09:16:49.959999Z","shell.execute_reply":"2022-01-07T09:16:51.299608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Mapping teams abbreviations to full name (got that from [NFL 2021 Rulebook](https://operations.nfl.com/the-rules/2021-nfl-rulebook/#team-abbreviation-codes))\n### We will also map a team name to NOAA weather stations to get weather data of games.","metadata":{}},{"cell_type":"code","source":"team_abb = {'ARI': ['Arizona Cardinals','PHOENIX DEER VALLEY MUNICIPAL AIRPORT, AZ US','NFC', 'west'],\n            'ATL': ['Atlanta Falcons','ATLANTA FULTON CO AIRPORT, GA US','NFC', 'south'],\n            'BAL': ['Baltimore Ravens', 'BALTIMORE WASHINGTON INTERNATIONAL AIRPORT, MD US','AFC', 'north'],\n            'BUF': ['Buffalo Bills','BUFFALO NIAGARA INTERNATIONAL, NY US','AFC', 'east'],\n            'CAR': ['Carolina Panthers','CHARLOTTE DOUGLAS AIRPORT, NC US','NFC', 'south'],\n            'CHI': ['Chicago Bears', 'CHICAGO MIDWAY AIRPORT, IL US','NFC', 'north'],\n            'CIN': ['Cincinnati Bengals', 'CINCINNATI MUNICIPAL AIRPORT LUNKEN FIELD, OH US','AFC', 'north'],\n            'CLE': ['Cleveland Browns','CLEVELAND BURKE LAKEFRONT AIRPORT, OH US','AFC', 'north'],\n            'DAL': ['Dallas Cowboys','DALLAS REDBIRD AIRPORT, TX US','NFC', 'east'],\n            'DEN': ['Denver Broncos','DENVER WATER DEPARTMENT, CO US','AFC', 'west'],\n            'DET': ['Detroit Lions', 'DETROIT CITY AIRPORT, MI US','NFC', 'north'],\n            'GB': ['Green Bay Packers','GREEN BAY A S INTERNATIONAL AIRPORT, WI US','NFC', 'north'],\n            'HOU': ['Houston Texans', 'HOUSTON WILLIAM P HOBBY AIRPORT, TX US','AFC', 'south'],\n            'IND': ['Indianapolis Colts', 'INDIANAPOLIS NWFO, IN US','AFC', 'south'],\n            'JAX': ['Jacksonville Jaguars','JACKSONVILLE CRAIG MUNICIPAL AIRPORT, FL US','AFC', 'south'],\n            'KC': ['Kansas City Chiefs', 'KANSAS CITY DOWNTOWN AIRPORT, MO US','AFC', 'west'],\n            'LV': ['Las Vegas Raiders', 'LAS VEGAS AIR TERMINAL, NV US','AFC', 'west'],\n            'LAC': ['Los Angeles Chargers','WHITTIER HILLS CALIFORNIA, CA US','AFC', 'west'],\n            'LA': ['Los Angeles Rams','WHITTIER HILLS CALIFORNIA, CA US','NFC', 'west'],\n            'MIA': ['Miami Dolphins','MIAMI OPA LOCKA AIRPORT, FL US','AFC', 'east'],\n            'MIN': ['Minnesota Vikings','UNIVERSITY OF MN ST. PAUL, MN US','NFC', 'north'],\n            'NE': ['New England Patriots', 'NORWOOD MEMORIAL AIRPORT, MA US','AFC', 'east'],\n            'NO': ['New Orleans Saints','NEW ORLEANS AUDUBON, LA US','NFC', 'south'],\n            'NYG': ['New York Giants','JFK INTERNATIONAL AIRPORT, NY US','NFC', 'east'],\n            'NYJ': ['New York Jets','JFK INTERNATIONAL AIRPORT, NY US','AFC', 'east'],\n            'OAK': ['Oakland Raiders', 'OAKLAND MUSEUM, CA US','AFC', 'west'],\n            'PHI': ['Philadelphia Eagles','PHILADELPHIA INTERNATIONAL AIRPORT, PA US','NFC', 'east'],\n            'PIT': ['Pittsburgh Steelers','PITTSBURGH ASOS, PA US','AFC', 'north'],\n            'SF': ['San Francisco 49ers','SAN JOSE INTERNATIONAL AIRPORT, CA US','NFC', 'west'],\n            'SEA': ['Seattle Seahawks', 'SEATTLE SAND POINT WEATHER FORECAST OFFICE, WA US','NFC', 'west'],\n            'TB': ['Tampa Bay Buccaneers', 'TAMPA INTERNATIONAL AIRPORT, FL US','NFC', 'south'],\n            'TEN': ['Tennessee Titans', 'NASHVILLE INTERNATIONAL AIRPORT, TN US','AFC', 'south'],\n            'WAS': ['Washington Football Team','OXON HILL, MD US','NFC', 'east']}","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:51.301823Z","iopub.execute_input":"2022-01-07T09:16:51.302167Z","iopub.status.idle":"2022-01-07T09:16:51.312906Z","shell.execute_reply.started":"2022-01-07T09:16:51.302128Z","shell.execute_reply":"2022-01-07T09:16:51.312357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we explore the temperature data collected from the NOAA","metadata":{}},{"cell_type":"code","source":"temperature.sample(8)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:51.313731Z","iopub.execute_input":"2022-01-07T09:16:51.314197Z","iopub.status.idle":"2022-01-07T09:16:51.339742Z","shell.execute_reply.started":"2022-01-07T09:16:51.314167Z","shell.execute_reply":"2022-01-07T09:16:51.339151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temperature = temperature.astype({'DATE':'datetime64[ns]'}).copy()\ntemperature['month'] = temperature.DATE.dt.month\ntemperature['city'] = temperature.NAME.str.extract(r'(^\\w+\\s\\w+)\\W')\ntemperature['STATE'] = temperature.NAME.str.extract(r'\\W(\\w{2})\\s\\w\\w$')\ntemperature.sort_values(by=['NAME','DATE'],inplace=True)\ntemperature = temperature[temperature.month.isin([12, 11, 10, 9, 1])].copy()\ntemperature.TMAX.fillna(method= 'ffill',inplace=True)\ntemperature.TMIN.fillna(method= 'ffill',inplace=True)\ntemperature.TAVG.fillna(temperature[['TMAX','TMIN']].mean(axis=1),inplace=True)\ntemperature.sample(4)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:51.34106Z","iopub.execute_input":"2022-01-07T09:16:51.341464Z","iopub.status.idle":"2022-01-07T09:16:52.872666Z","shell.execute_reply.started":"2022-01-07T09:16:51.341431Z","shell.execute_reply":"2022-01-07T09:16:52.871839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Finaly we merge temperature dataframe with the games one","metadata":{}},{"cell_type":"markdown","source":"### First we make a key from the games dataframe","metadata":{}},{"cell_type":"code","source":"games['home_key'] = games.homeTeamAbbr.apply(lambda x: team_abb[x][1])","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:52.873993Z","iopub.execute_input":"2022-01-07T09:16:52.874524Z","iopub.status.idle":"2022-01-07T09:16:52.880988Z","shell.execute_reply.started":"2022-01-07T09:16:52.874483Z","shell.execute_reply":"2022-01-07T09:16:52.880042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"games = games.reset_index().merge(temperature, left_on= ['gameDate','home_key'],how='left', right_on=['DATE','NAME']).copy()\ngames = games[['gameId','season', 'week', 'gameDate', 'gameTimeEastern', 'homeTeamAbbr',\n                 'visitorTeamAbbr', 'home_key', 'TAVG', 'month', 'STATE']].copy()\ngames.month = games.gameDate.dt.month_name()\ngames['home_conference'] = games.homeTeamAbbr.apply(lambda x: team_abb[x][-2])\ngames['away_conference'] = games.visitorTeamAbbr.apply(lambda x: team_abb[x][-2])\ngames['home_region'] = games.homeTeamAbbr.apply(lambda x: team_abb[x][-1])\ngames['away_region'] = games.visitorTeamAbbr.apply(lambda x: team_abb[x][-1])\ngames['home_division'] = games.home_conference + ' ' + games.home_region\ngames['away_division'] = games.away_conference + ' ' + games.away_region\ngames[games.TAVG.isna()]","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:52.882579Z","iopub.execute_input":"2022-01-07T09:16:52.883108Z","iopub.status.idle":"2022-01-07T09:16:52.926441Z","shell.execute_reply.started":"2022-01-07T09:16:52.883046Z","shell.execute_reply":"2022-01-07T09:16:52.925573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting a list of states","metadata":{}},{"cell_type":"code","source":"games.STATE.unique()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:52.927555Z","iopub.execute_input":"2022-01-07T09:16:52.92778Z","iopub.status.idle":"2022-01-07T09:16:52.934407Z","shell.execute_reply.started":"2022-01-07T09:16:52.927755Z","shell.execute_reply":"2022-01-07T09:16:52.93337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we make a mapping for states timezone (only the difference from EST)","metadata":{}},{"cell_type":"code","source":"state_time = {'PA': 0 , 'MD': 0, 'OH': 0, 'IN': 0, 'FL': 0, 'MA': 0, 'LA': -1, 'NY': 0, 'AZ': -2, 'NC': 0, 'WI': -1,\n              'MI': 0, 'CA': -3, 'GA': 0, 'TN': -1, 'CO': -2, 'TX': -1, 'IL': -1, 'MO': -1, 'MN': -1, 'WA': -3,'NV': -3}\ngames['time_zone_adj'] = games.STATE.apply(lambda x: state_time[x])\ngames['gameTimeLocal'] = games.gameTimeEastern.apply(lambda x: int(x[:2])) + games.time_zone_adj\ngames['gameTimeLocal'] = games['gameTimeLocal'].astype(str) + games.gameTimeEastern.apply(lambda x: x[2:-3]).copy()\ngames.drop(columns='time_zone_adj', inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:52.935531Z","iopub.execute_input":"2022-01-07T09:16:52.936059Z","iopub.status.idle":"2022-01-07T09:16:52.953652Z","shell.execute_reply.started":"2022-01-07T09:16:52.936029Z","shell.execute_reply":"2022-01-07T09:16:52.95289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"games.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:52.954769Z","iopub.execute_input":"2022-01-07T09:16:52.955476Z","iopub.status.idle":"2022-01-07T09:16:52.981066Z","shell.execute_reply.started":"2022-01-07T09:16:52.955445Z","shell.execute_reply":"2022-01-07T09:16:52.980498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we check plays and PFFScoutingData datasets","metadata":{}},{"cell_type":"code","source":"PFFScoutingData.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:52.982298Z","iopub.execute_input":"2022-01-07T09:16:52.9827Z","iopub.status.idle":"2022-01-07T09:16:53.008657Z","shell.execute_reply.started":"2022-01-07T09:16:52.982673Z","shell.execute_reply":"2022-01-07T09:16:53.008049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plays.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:53.009641Z","iopub.execute_input":"2022-01-07T09:16:53.01017Z","iopub.status.idle":"2022-01-07T09:16:53.038622Z","shell.execute_reply.started":"2022-01-07T09:16:53.010135Z","shell.execute_reply":"2022-01-07T09:16:53.038078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### `playDescription` columns seems to be interesting as it have a text describing the play","metadata":{}},{"cell_type":"markdown","source":"### Adding `yards to end zone` feature to the plays dataframe","metadata":{}},{"cell_type":"code","source":"plays['yards_to_endzone'] = np.select([plays.possessionTeam == plays.yardlineSide,plays.possessionTeam != plays.yardlineSide],\n          [((plays.possessionTeam == plays.yardlineSide).astype(int) * (100 - plays.yardlineNumber)), plays.yardlineNumber], default=50)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:53.039837Z","iopub.execute_input":"2022-01-07T09:16:53.040253Z","iopub.status.idle":"2022-01-07T09:16:53.052833Z","shell.execute_reply.started":"2022-01-07T09:16:53.040226Z","shell.execute_reply":"2022-01-07T09:16:53.052054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Engineering PreSnapscores features to show the score of team in possession and the receiving team in addtion to the score difference instead of only dealing with home and visitor labels","metadata":{}},{"cell_type":"code","source":"temp_plays = plays.merge(games, left_on= 'gameId', right_on='gameId')\nplays['pos_pre_score'] = np.select([(temp_plays.possessionTeam == temp_plays.homeTeamAbbr),(temp_plays.possessionTeam == temp_plays.visitorTeamAbbr)],[temp_plays.preSnapHomeScore, temp_plays.preSnapVisitorScore], default= 100000)\nplays['def_pre_score'] = np.select([(temp_plays.possessionTeam != temp_plays.homeTeamAbbr),(temp_plays.possessionTeam != temp_plays.visitorTeamAbbr)],[temp_plays.preSnapHomeScore, temp_plays.preSnapVisitorScore], default= 100000)\nplays['pos_score_def'] = plays.pos_pre_score - plays.def_pre_score\ndel temp_plays\nplays.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:16:53.0603Z","iopub.execute_input":"2022-01-07T09:16:53.061133Z","iopub.status.idle":"2022-01-07T09:16:53.135903Z","shell.execute_reply.started":"2022-01-07T09:16:53.061074Z","shell.execute_reply":"2022-01-07T09:16:53.135182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='EDA'></a>\n# Exploratory Data Analysis","metadata":{}},{"cell_type":"markdown","source":"## This part will go through a complete EDA to explore all datasets\n### We will be exploring the following datasets\n* #### [Games](#gms).\n* #### [Players](#players).\n* #### [plays](#plays).\n* #### [PFFScoutingData](#Epff).\n* #### [Tracking data](#trk). ","metadata":{}},{"cell_type":"markdown","source":"<a id='gms'></a>\n\n## First we explore games dataset","metadata":{}},{"cell_type":"markdown","source":"### We start first by showing games played inb each state given the conference","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(14,5))\nsns.countplot(data=games, x= 'STATE',hue='home_conference',palette=['blue','red'], alpha=.8)\nplt.title('Games played in each state given the conference',fontsize=18)\nplt.legend(title='Conference', title_fontsize=12)\nplt.tick_params(labelsize=14)\nplt.ylabel('')\nplt.xlabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:53.137134Z","iopub.execute_input":"2022-01-07T09:16:53.137361Z","iopub.status.idle":"2022-01-07T09:16:53.696281Z","shell.execute_reply.started":"2022-01-07T09:16:53.137338Z","shell.execute_reply":"2022-01-07T09:16:53.695459Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we check game time","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(15,6))\nsns.countplot(data=games, x='gameTimeEastern',color='darkblue',\n              order=sorted(games.gameTimeEastern.unique()), alpha=.7)\nplt.title('Games Starting time (EST)',fontsize=18)\nplt.legend(title='Conference', title_fontsize=12)\nplt.tick_params(labelsize=12,rotation=290)\nplt.yticks(rotation=0)\nplt.ylabel('')\nplt.xlabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:53.69743Z","iopub.execute_input":"2022-01-07T09:16:53.697632Z","iopub.status.idle":"2022-01-07T09:16:54.083007Z","shell.execute_reply.started":"2022-01-07T09:16:53.697609Z","shell.execute_reply":"2022-01-07T09:16:54.082187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(18,6))\nsns.countplot(data=games, x='gameTimeLocal',color='darkblue',\n              order=sorted(games.gameTimeLocal.unique()), alpha=.7)\nplt.title('Games Starting time (local time)',fontsize=18)\nplt.tick_params(labelsize=12,rotation=290)\nplt.yticks(rotation=0)\nplt.ylabel('')\nplt.xlabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:54.084607Z","iopub.execute_input":"2022-01-07T09:16:54.085237Z","iopub.status.idle":"2022-01-07T09:16:54.604251Z","shell.execute_reply.started":"2022-01-07T09:16:54.085197Z","shell.execute_reply":"2022-01-07T09:16:54.603371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we get the average temperature of air in each week","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(22,6))\nsns.pointplot(data=games, x='week',y='TAVG', palette='viridis_r', hue='season', dodge=.3,markers= '^', linestyles=':')#,ci=99.9, palette='icefire_r', alpha= .8)\nplt.ylabel('Average Temperature in F',fontsize=15)\nplt.xlabel('Week', fontsize= 15)\nplt.title('Average air temperature for each game week',fontsize=18)\nplt.xticks(fontsize=14)\nplt.yticks(fontsize=12);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:54.605627Z","iopub.execute_input":"2022-01-07T09:16:54.605941Z","iopub.status.idle":"2022-01-07T09:16:56.33829Z","shell.execute_reply.started":"2022-01-07T09:16:54.605904Z","shell.execute_reply":"2022-01-07T09:16:56.337358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='players'></a>\n## Exploring players dataset","metadata":{}},{"cell_type":"markdown","source":"### First we show the number of each player in each position (as this may afffect the overall avarage of any players statistics)","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(16,6))\nax = fig.add_subplot(111)\nsns.countplot(data=players, x ='Position',ax=ax, palette='viridis', order=players.Position.value_counts().index, alpha=.9)\nplt.title('Counts of each player in every position', fontsize=22)\nplt.xticks(fontsize=14)\nplt.yticks(fontsize=14)\nplt.ylabel('')\nplt.xlabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:56.33946Z","iopub.execute_input":"2022-01-07T09:16:56.339734Z","iopub.status.idle":"2022-01-07T09:16:56.797713Z","shell.execute_reply.started":"2022-01-07T09:16:56.3397Z","shell.execute_reply":"2022-01-07T09:16:56.796839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### now we explore Players' heights and weights\n### We start with players heights","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(10,5))\nax = fig.add_subplot(111)\nsns.kdeplot(data=players, x ='highcm', linewidth=0,fill=True,alpha=.4)\nplt.title(\"Players' heights KDE plot\", fontsize=16);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:56.799244Z","iopub.execute_input":"2022-01-07T09:16:56.799694Z","iopub.status.idle":"2022-01-07T09:16:57.090504Z","shell.execute_reply.started":"2022-01-07T09:16:56.799657Z","shell.execute_reply":"2022-01-07T09:16:57.089705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### Even if hegihts look smooth it still looks like is a mixture of gaussians distributions ","metadata":{}},{"cell_type":"markdown","source":"### Showing a box plot of height for each player position","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(20,7))\nax = fig.add_subplot(111)\nsns.boxplot(data=players, y = 'highcm', x='Position',order= players.groupby('Position')['highcm'].mean().sort_values(ascending=False).index, ax=ax, palette='viridis')\nplt.title(\"Players' heights for every position\", fontsize=20)\nplt.xticks(fontsize=14)\nplt.yticks(fontsize=14)\nplt.ylabel('')\nplt.xlabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:57.092021Z","iopub.execute_input":"2022-01-07T09:16:57.09249Z","iopub.status.idle":"2022-01-07T09:16:57.786006Z","shell.execute_reply.started":"2022-01-07T09:16:57.092449Z","shell.execute_reply":"2022-01-07T09:16:57.785197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### The next figure is just to get a deeper look into each position distribution and how it differs from the overall mean","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(22,26))\ngrid =  gridspec.GridSpec(7,4,figure=fig,hspace=.35,wspace=.2)\npositions_and_means = list(zip(players.groupby('Position')['highcm'].mean().index,players.groupby('Position')['highcm'].mean()))\nheight_mean = players.highcm.mean() \nn =0\nfor i in range(7):\n    for j in range(4):\n        ax = fig.add_subplot(grid[i, j])\n        pos = positions_and_means[n][0]\n        sns.kdeplot(data= players[players.Position == pos ], x='highcm',ax=ax, color='darkblue',alpha=.4,linewidth=0,fill=True)\n        ax.axvline(positions_and_means[n][1],label='Pos μ= {}'.format(round(positions_and_means[n][1],2)),color = 'orangered',linestyle ='--',alpha=.7)\n        ax.axvline(height_mean,label='Ovr μ= {}'.format(round(height_mean,2)), color='blue',linestyle ='--',alpha=.7)\n        ax.set_title('Position: '+positions_and_means[n][0],fontsize=14)\n        ax.set_xlabel('')\n        ax.set_ylabel('')\n        ax.set_xlim(167,206)\n        plt.legend(loc='upper left',fontsize= 10)\n        n += 1\n        if n ==26:\n            break\nfig.suptitle('Kde plot of players\\' heights for every position', fontsize=16,y=.9);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:16:57.787217Z","iopub.execute_input":"2022-01-07T09:16:57.787447Z","iopub.status.idle":"2022-01-07T09:17:04.423769Z","shell.execute_reply.started":"2022-01-07T09:16:57.787422Z","shell.execute_reply":"2022-01-07T09:17:04.423161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we check players weights in the very same way","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(10,5))\nax = fig.add_subplot(111)\nsns.kdeplot(data=players, x ='weight', linewidth=0,fill=True,alpha=.4,color='darkblue')\nplt.title(\"Players' weight KDE plot\", fontsize=16);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:04.424778Z","iopub.execute_input":"2022-01-07T09:17:04.425256Z","iopub.status.idle":"2022-01-07T09:17:04.667076Z","shell.execute_reply.started":"2022-01-07T09:17:04.425209Z","shell.execute_reply":"2022-01-07T09:17:04.666516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### weights distribution seems a little different from heights as it looks like some kind of a trimodal distribution","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(20,7))\nax = fig.add_subplot(111)\nsns.boxplot(data=players, y = 'weight', x='Position',order= players.groupby('Position')['weight'].mean().sort_values(ascending=False).index, ax=ax, palette='viridis')\nplt.title(\"Players' weight for every position\", fontsize=20)\nplt.xticks(fontsize=14)\nplt.yticks(fontsize=14)\nplt.ylabel('')\nplt.xlabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:04.667979Z","iopub.execute_input":"2022-01-07T09:17:04.668773Z","iopub.status.idle":"2022-01-07T09:17:05.288546Z","shell.execute_reply.started":"2022-01-07T09:17:04.668739Z","shell.execute_reply":"2022-01-07T09:17:05.287981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = plt.figure(figsize=(22,26))\ngrid =  gridspec.GridSpec(7,4,figure=fig,hspace=.35,wspace=.2)\npositions_and_means = list(zip(players.groupby('Position')['weight'].mean().index,players.groupby('Position')['weight'].mean()))\nweight_mean = players.weight.mean() \nn =0\nfor i in range(7):\n    for j in range(4):\n        ax = fig.add_subplot(grid[i, j])\n        pos = positions_and_means[n][0]\n        sns.kdeplot(data= players[players.Position == pos ], x='weight',ax=ax, color='darkblue',alpha=.4,linewidth=0,fill=True)\n        ax.axvline(positions_and_means[n][1],label='Pos μ= {}'.format(round(positions_and_means[n][1],2)),color = 'orange',linestyle ='--',alpha=.7)\n        ax.axvline(weight_mean,label='Ovr μ= {}'.format(round(weight_mean,2)), color='blue',linestyle ='--',alpha=.7)\n        ax.set_title('Position: '+positions_and_means[n][0],fontsize=14)\n        ax.set_xlabel('')\n        ax.set_ylabel('')\n        ax.set_xlim(153,380)\n        plt.legend(loc='upper right',fontsize= 10)\n        n += 1\n        if n ==26:\n            break\nfig.suptitle('Kde plot of players\\' weights for every position', fontsize=16,y=.9);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:05.289577Z","iopub.execute_input":"2022-01-07T09:17:05.290244Z","iopub.status.idle":"2022-01-07T09:17:10.714058Z","shell.execute_reply.started":"2022-01-07T09:17:05.290213Z","shell.execute_reply":"2022-01-07T09:17:10.713189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### Weights seems to differ from the overall mean in a more obvious way from heights","metadata":{}},{"cell_type":"markdown","source":"### The next figure shows the overall relation between height and weight","metadata":{}},{"cell_type":"code","source":"g = sns.jointplot(data=players, y = 'weight', x='highcm',kind='reg',height=8,ratio=8,space=.1)\ng.set_axis_labels(xlabel='Height (cm)', ylabel= 'Weight (lb)',fontsize=14);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:10.715257Z","iopub.execute_input":"2022-01-07T09:17:10.715494Z","iopub.status.idle":"2022-01-07T09:17:11.543505Z","shell.execute_reply.started":"2022-01-07T09:17:10.715466Z","shell.execute_reply":"2022-01-07T09:17:11.542642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='plays'></a>\n## Exploring the plays data sets","metadata":{}},{"cell_type":"markdown","source":"### First we get a summary of the plays dataset","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(16,12))\ngrid =  gridspec.GridSpec(2,2 ,figure=fig, hspace=.1,wspace=.15 )\nax1 = fig.add_subplot(grid[0, 0])\nax2 = fig.add_subplot(grid[0, 1])\ncolors= [( 1.00, .682, .102),\n         (.455, .569, .914),\n         (0.477504, 0.821444, 0.318195),\n         (0.134692, 0.658636, 0.517649)]\npatches, texts, nums  = ax1.pie(x= plays.specialTeamsPlayType.value_counts()\n                      , wedgeprops=dict(width=0.55,linewidth= 0),startangle=305,\n                      center=(.2,.5),radius=1.1,colors=colors,autopct='%.1f%%',\n                      textprops=dict(fontsize=14),)\nax1.legend(patches, plays.specialTeamsPlayType.value_counts().index, bbox_to_anchor=[0.1, 0.25],fontsize=11, title='Play type', title_fontsize=13)\n\nax1.set_title('Count of each play type', fontsize=18)\nsns.kdeplot(data=plays[~plays.specialTeamsPlayType.isin(['Kickoff','Extra Point'])],\n            x='yards_to_endzone',hue='specialTeamsPlayType',fill=True,linewidth=0,palette=['orange','darkblue'], ax= ax2,alpha=.5)\nax2.set_title('play type and yards to endzone', fontsize=18)\nax1.set_ylabel('')\nax2.set_ylabel('')\nax1.set_xlabel('', fontsize=14)\nax2.set_xlabel('',fontsize=14)\n\nax3 = fig.add_subplot(grid[1, 0])\nax4 = fig.add_subplot(grid[1, 1])\n\nsns.scatterplot(data= plays, x='yards_to_endzone', y='kickLength',hue='specialTeamsPlayType',s=110,alpha=.4, ax=ax3,palette='viridis')\n\nsns.kdeplot(data= plays[(plays.specialTeamsPlayType.isin(['Field Goal','punt']))],palette= 'viridis',\n            hue='specialTeamsResult', x='pos_score_def',fill=True, alpha=.7, ax= ax4,\n            hue_order=list(plays[(plays.specialTeamsPlayType.isin(['Field Goal','punt']))].specialTeamsResult.value_counts().sort_values().index))\nax3.legend(fontsize=11, title='Play type', title_fontsize=13)\nax3.set_ylabel('kick Length', fontsize=14)\nax3.set_xlabel('yards to end zone', fontsize=14)\nax4.set_ylabel('')\nax4.set_xlabel('Pos team score differnce',fontsize=14)\nfig.suptitle('Plays dataset summary', y=.94, fontsize=22);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:11.544703Z","iopub.execute_input":"2022-01-07T09:17:11.544903Z","iopub.status.idle":"2022-01-07T09:17:13.930262Z","shell.execute_reply.started":"2022-01-07T09:17:11.544879Z","shell.execute_reply":"2022-01-07T09:17:13.929359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### The next figure shows a summary of each special team play result","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(17,12))\ngrid =  gridspec.GridSpec(2,2 ,figure=fig, hspace=.2,wspace=.4 )\n\nax1 = fig.add_subplot(grid[0, 0])\nax2 = fig.add_subplot(grid[0, 1])\nax3 = fig.add_subplot(grid[1, 0])\nax4 = fig.add_subplot(grid[1, 1])\nfor t,x in zip(plays.specialTeamsPlayType.unique(), (ax1,ax2,ax3,ax4)):\n    sns.countplot(data=plays[plays.specialTeamsPlayType == t], y='specialTeamsResult',\n                  order= plays[plays.specialTeamsPlayType == t].specialTeamsResult.value_counts().index,color='darkblue',alpha=.6, ax=x)\n    x.set_title('Results of {} plays'.format(t),fontsize=16)\n    x.set_ylabel('')\n    x.set_xlabel('')\n    x.tick_params(axis='y', labelsize=11)\n    x.tick_params(axis='x', labelsize=13)\nfig.suptitle('Result summary of  each kind of Special teams plays', fontsize= 20, y=.95);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:13.931598Z","iopub.execute_input":"2022-01-07T09:17:13.931845Z","iopub.status.idle":"2022-01-07T09:17:14.756177Z","shell.execute_reply.started":"2022-01-07T09:17:13.931815Z","shell.execute_reply":"2022-01-07T09:17:14.755373Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we take a deeper look into yards to end zone special teams plays \n#### P.s we will explore Punts and Field goals only since kick offs and extra points have fixed starting yardage","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(18, 7))\ngrid =  gridspec.GridSpec(1, 2, figure=fig, hspace=.18,wspace=.1 )\nax1 = fig.add_subplot(grid[0, 0])\nax2 = fig.add_subplot(grid[0, 1:])\n\npunt_l = list(plays[(plays.specialTeamsPlayType.isin(['Punt']))].specialTeamsResult.value_counts().sort_values(ascending=True).index)\nsns.kdeplot(data=plays[(plays.specialTeamsPlayType.isin(['Punt']))],\n            x='yards_to_endzone',hue='specialTeamsResult',hue_order=punt_l,fill=True,linewidth=1,palette= 'viridis', alpha=.7, ax=ax1)\nfgoal_l = ['Kick Attempt Good','Kick Attempt No Good','Non-Special Teams Result', 'Blocked Kick Attempt']\nsns.kdeplot(data=plays[(plays.specialTeamsPlayType.isin(['Field Goal'])) & (plays.specialTeamsResult.isin(fgoal_l))],\n            x='yards_to_endzone',hue='specialTeamsResult',hue_order=fgoal_l[::-1],fill=True,linewidth=1,palette='viridis', alpha=.7, ax=ax2)\nax1.set_title('Punts results distributions', fontsize=16)\nax2.set_title('Field goal results distributions', fontsize=16)\nfig.suptitle('Yards to end zone and special teams plays results distributions', fontsize=22)\nax1.set_ylabel('')\nax2.set_ylabel('');","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:14.757541Z","iopub.execute_input":"2022-01-07T09:17:14.757767Z","iopub.status.idle":"2022-01-07T09:17:15.508815Z","shell.execute_reply.started":"2022-01-07T09:17:14.75774Z","shell.execute_reply":"2022-01-07T09:17:15.507914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='Epff'></a>\n### Exploring the PFFScoutingData dataset","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(16,12))\ngrid =  gridspec.GridSpec(2,2 ,figure=fig, hspace=.2,wspace=.15 )\nax1 = fig.add_subplot(grid[0, 0])\nax2 = fig.add_subplot(grid[0, 1])\nax3 = fig.add_subplot(grid[1, 0:])\n\nsns.countplot(data= PFFScoutingData, x = 'kickDirectionIntended',\n              hue= 'kickDirectionActual', palette='viridis', ax= ax1)\nax1.set_title('Count of kick  given the direction (intended vs real)', fontsize=16)\nax1.set_ylabel('')\nax1.set_xlabel('direction intended', fontsize=14)\nax1.legend(loc= 'upper right', fontsize= 10, title= 'Actual direction', title_fontsize=12)\nsns.countplot(data= PFFScoutingData, x = 'kickType',\n              hue= 'kickDirectionActual', palette='viridis', ax= ax2)\nax2.set_title( 'Count of each kick type given the direction', fontsize=16)\nax2.set_ylabel('')\nax2.set_xlabel('')\nax2.legend(loc= 'upper right', fontsize= 10, title= 'Kick direction', title_fontsize=12)\nsns.kdeplot(data= PFFScoutingData,  hue= 'kickType',x= 'hangTime',hue_order= list(PFFScoutingData.kickType.value_counts().sort_values().index),\n            palette='colorblind', fill=True, ax= ax3, alpha=.7)\nax3.set_title('KDE plot of hanging time giving the type of each kick', fontsize= 16)\nax3.set_ylabel('')\nfig.suptitle('PFFScoutingData Summary', fontsize = 22, y=.94);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:15.510269Z","iopub.execute_input":"2022-01-07T09:17:15.510729Z","iopub.status.idle":"2022-01-07T09:17:16.627947Z","shell.execute_reply.started":"2022-01-07T09:17:15.510688Z","shell.execute_reply":"2022-01-07T09:17:16.627057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='trk'></a>\n## Now we explore the tracking datasets\n### We start by doing some aggregation","metadata":{}},{"cell_type":"code","source":"try:\n    tracking2018.groupby(['displayName','gameId','playId']).agg({'dis' : 'sum', 's':'mean','team':st.mode}).reset_index()\nexcept:\n    print(colored('Guess what?!, ...It happened!',color = 'red'))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:16.629413Z","iopub.execute_input":"2022-01-07T09:17:16.62975Z","iopub.status.idle":"2022-01-07T09:17:21.276956Z","shell.execute_reply.started":"2022-01-07T09:17:16.629709Z","shell.execute_reply":"2022-01-07T09:17:21.27593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center><img src=\"https://c.tenor.com/FkEo2jYLDrYAAAAd/what-a-coincidence-reassure.gif\"></center>","metadata":{}},{"cell_type":"code","source":"t_df = tracking2018.groupby(['displayName','gameId','playId']).agg({'dis' : 'sum', 's':'mean','team':lambda x: [i for i in x]}).reset_index().copy()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:21.278468Z","iopub.execute_input":"2022-01-07T09:17:21.278768Z","iopub.status.idle":"2022-01-07T09:17:26.328038Z","shell.execute_reply.started":"2022-01-07T09:17:21.27873Z","shell.execute_reply":"2022-01-07T09:17:26.327122Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Investigating this (don't judge me, I just need to know )","metadata":{}},{"cell_type":"code","source":"for n, i in enumerate(t_df.team.values):\n    for j in i:\n        if j != i[0]:\n            print(n)\n            break","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:26.329287Z","iopub.execute_input":"2022-01-07T09:17:26.32951Z","iopub.status.idle":"2022-01-07T09:17:27.380315Z","shell.execute_reply.started":"2022-01-07T09:17:26.329486Z","shell.execute_reply":"2022-01-07T09:17:27.379241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t_df.iloc[106540,:]","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:27.383062Z","iopub.execute_input":"2022-01-07T09:17:27.383436Z","iopub.status.idle":"2022-01-07T09:17:27.39126Z","shell.execute_reply.started":"2022-01-07T09:17:27.383392Z","shell.execute_reply":"2022-01-07T09:17:27.390412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking2018[(tracking2018.gameId==2018093011) & (tracking2018.playId == 3604) & (tracking2018.displayName == 'Michael Thomas')].sample(10)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:27.392296Z","iopub.execute_input":"2022-01-07T09:17:27.392528Z","iopub.status.idle":"2022-01-07T09:17:28.21633Z","shell.execute_reply.started":"2022-01-07T09:17:27.392505Z","shell.execute_reply":"2022-01-07T09:17:28.215785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Told ya, it happens!! .. two `Michael Thomas` same game same play, different teams! \n<center><img src=\"https://c.tenor.com/QXVs4QWLlzkAAAAC/spider-man.gif\"  width='500' height=\"500\"></center>","metadata":{}},{"cell_type":"markdown","source":"### Now We fix this problem and make an aggregation for the three seasons by each player and each play","metadata":{}},{"cell_type":"code","source":"del t_df\ntracking18_agg = tracking2018.groupby(['nflId','displayName', 'jerseyNumber', 'position', 'team','gameId','playId']).agg({'time':'min', 'dis' : 'sum', 's':['mean','max','min'],'a':['mean','max','min']}).copy()\ntracking19_agg = tracking2019.groupby(['nflId','displayName', 'jerseyNumber', 'position', 'team','gameId','playId']).agg({'time':'min', 'dis' : 'sum', 's':['mean','max','min'],'a':['mean','max','min']}).copy()\ntracking20_agg = tracking2020.groupby(['nflId','displayName', 'jerseyNumber', 'position', 'team','gameId','playId']).agg({'time':'min', 'dis' : 'sum', 's':['mean','max','min'],'a':['mean','max','min']}).copy()\ntracking18_agg.columns = ['beg_time', 'dis_sum', 's_mean', 's_max', 's_min', 'a_mean', 'a_max', 'a_min']\ntracking19_agg.columns = ['beg_time', 'dis_sum', 's_mean', 's_max', 's_min', 'a_mean', 'a_max', 'a_min']\ntracking20_agg.columns = ['beg_time', 'dis_sum', 's_mean', 's_max', 's_min', 'a_mean', 'a_max', 'a_min']\ntracking18_agg.reset_index(inplace= True)\ntracking19_agg.reset_index(inplace= True)\ntracking20_agg.reset_index(inplace= True)\ntracking18_agg = tracking18_agg.merge(games, how= 'inner', left_on= 'gameId',right_on='gameId').merge(plays, left_on= ['gameId','playId'], right_on = ['gameId','playId']).merge(players, left_on= ['nflId'], right_on=['nflId']).copy()\ntracking19_agg = tracking19_agg.merge(games, how= 'inner', left_on= 'gameId',right_on='gameId').merge(plays, left_on= ['gameId','playId'], right_on = ['gameId','playId']).merge(players, left_on= ['nflId'], right_on=['nflId']).copy()\ntracking20_agg = tracking20_agg.merge(games, how= 'inner', left_on= 'gameId',right_on='gameId').merge(plays, left_on= ['gameId','playId'], right_on = ['gameId','playId']).merge(players, left_on= ['nflId'], right_on=['nflId']).copy()\ngc.collect()\ntracking18_agg.sample(4)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:28.21748Z","iopub.execute_input":"2022-01-07T09:17:28.218076Z","iopub.status.idle":"2022-01-07T09:17:44.020039Z","shell.execute_reply.started":"2022-01-07T09:17:28.218044Z","shell.execute_reply":"2022-01-07T09:17:44.019005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### checking again for duplicated names problem","metadata":{}},{"cell_type":"code","source":"tracking18_agg[(tracking18_agg.playId == 3604) & (tracking18_agg.displayName_x == 'Michael Thomas')]","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:44.021314Z","iopub.execute_input":"2022-01-07T09:17:44.021532Z","iopub.status.idle":"2022-01-07T09:17:44.075941Z","shell.execute_reply.started":"2022-01-07T09:17:44.021507Z","shell.execute_reply":"2022-01-07T09:17:44.075312Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center><img src=\"https://c.tenor.com/790jxHUkKLIAAAAC/loser-joey.gif\" width='500' height=\"500\"></center>","metadata":{}},{"cell_type":"markdown","source":"### Merging it all together","metadata":{}},{"cell_type":"code","source":"tracking_agg = pd.concat([tracking18_agg, tracking19_agg, tracking20_agg], ignore_index=True, sort=False)\ntracking_agg['team_name'] = np.select([tracking_agg.team =='home' ,tracking_agg.team =='away'], [tracking_agg.homeTeamAbbr, tracking_agg.visitorTeamAbbr])\ntracking_agg['side'] = np.where(tracking_agg.possessionTeam == tracking_agg.team_name, 'offense','defense')\ntracking_agg['team_conference'] = tracking_agg.team_name.apply(lambda x: team_abb[x][-2])\ntracking_agg['team_region'] = tracking_agg.team_name.apply(lambda x: team_abb[x][-1])\ntracking_agg['team_division'] = tracking_agg.team_conference + ' ' + tracking_agg.team_region\ntracking_agg.displayName_x = tracking_agg.displayName_x.str.lower().copy()\ntracking_agg.displayName_y = tracking_agg.displayName_y.str.lower().copy()\ntracking_agg.playDescription = tracking_agg.playDescription.str.lower().copy()\n\ntracking_agg['displayName_x_abb'] = tracking_agg.displayName_x.apply(lambda nm : str(nm)[0]+'.')\ntracking_agg['displayName_x_abb'] = tracking_agg.displayName_x_abb + tracking_agg.displayName_x.str.extract('\\s(\\w+)').loc[:,0]\ntracking_agg['displayName_y_abb'] = tracking_agg.displayName_y.apply(lambda nm : str(nm)[0]+'.')\ntracking_agg['displayName_y_abb'] = tracking_agg.displayName_y_abb + tracking_agg.displayName_y.str.extract('\\s(\\w+)').loc[:,0]\ndel tracking18_agg, tracking19_agg, tracking20_agg\nl = []\nfor name_x_ab, name_y_ab, name_x, name_y, playdes in zip(tracking_agg.displayName_x_abb,\n                                   tracking_agg.displayName_y_abb,\n                                   tracking_agg.displayName_x,\n                                   tracking_agg.displayName_y,\n                                   tracking_agg.playDescription):\n    if (name_x_ab in playdes) or (name_y_ab in playdes) or(name_x in playdes) or (name_y in playdes):\n        l.append('key player')\n    else:\n        l.append('non key player')\ntracking_agg['player_is_key'] = l\ngc.collect()\ntracking_agg.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:17:44.077103Z","iopub.execute_input":"2022-01-07T09:17:44.077523Z","iopub.status.idle":"2022-01-07T09:17:48.601962Z","shell.execute_reply.started":"2022-01-07T09:17:44.077484Z","shell.execute_reply":"2022-01-07T09:17:48.601182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<center><img src=\"https://c.tenor.com/Oc4nf8N08jIAAAAd/mind-blow-galaxy.gif\"  width='500' height=\"500\"></center>","metadata":{}},{"cell_type":"markdown","source":"### Clarification\n#### `side` feature added above is meant whether the player in on the team with the ball or not as offense mean that player is with the team that have the possession and defense if not (and not to be confused with fotball offense adn defense teams)","metadata":{}},{"cell_type":"markdown","source":"## Distance covered and speed\n### In this part will be look into the distance covered and speed of players ","metadata":{}},{"cell_type":"markdown","source":"### First we make a KDE plot of average distance ran by a player","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(10,6))\nsns.kdeplot(data=tracking_agg, x='dis_sum', hue= 'season', fill=False, palette='viridis',linewidth=2)\nplt.title('Average distance ran by a player in a play', fontsize=18);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:48.603118Z","iopub.execute_input":"2022-01-07T09:17:48.603359Z","iopub.status.idle":"2022-01-07T09:17:51.264811Z","shell.execute_reply.started":"2022-01-07T09:17:48.603332Z","shell.execute_reply":"2022-01-07T09:17:51.264226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### Distance covered by a players seems to vary a lot","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(10,8))\nsns.scatterplot(y= 's_mean', x= 'dis_sum', data= tracking_agg,s=100, palette= 'viridis',hue='position', alpha=.7)\nplt.title('Relation between speed and distance made by each player in a play',fontsize=16)\nplt.legend(loc='lower right',ncol=2,title='Position',title_fontsize=14);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:17:51.265987Z","iopub.execute_input":"2022-01-07T09:17:51.266242Z","iopub.status.idle":"2022-01-07T09:18:10.765854Z","shell.execute_reply.started":"2022-01-07T09:17:51.266214Z","shell.execute_reply":"2022-01-07T09:18:10.765006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ((ax11, ax12, ax13, ax14),(ax21, ax22, ax23, ax24)) = plt.subplots(2,4, figsize=(24,10))\nplt.subplots_adjust(hspace=.25)\nsns.barplot(x= 'season', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='viridis', hue='side',alpha=.9,ax=ax11)\nax11.set_title('Side in the play',fontsize= 16)\nax11.set_xticks([-1,0,1,2,3])\nax11.set_xticklabels(['',2018, 2019, 2020,''])\nax11.tick_params(labelsize=14)\nax11.set_ylabel('Distance (yards)',fontsize=14)\nax11.set_xlabel('')\nax11.legend(ncol=1,fontsize=10,title='Side',title_fontsize= 12,loc='lower right');\n\nsns.barplot(x= 'season', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='viridis', hue='team', alpha=.9,ax=ax12)\nax12.set_title('Player team',fontsize=16)\nax12.set_xticks([-1,0,1,2,3])\nax12.set_xticklabels(['',2018, 2019, 2020,''])\nax12.tick_params(labelsize=14)\nax12.set_ylabel('')\nax12.set_xlabel('')\nax12.legend(ncol=1,fontsize=10,title='Team',title_fontsize= 12,loc='lower right');\n\nsns.barplot(x= 'season', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='viridis', hue='quarter',alpha=.9,ax=ax13)\nax13.set_title('Quarter',fontsize=16)\nax13.set_xticks([-1,0,1,2,3])\nax13.set_xticklabels(['',2018, 2019, 2020,''])\nax13.tick_params(labelsize=14)\nax13.set_ylabel('')\nax13.set_xlabel('')\nax13.legend(ncol=1,fontsize=10,title='Quarter',title_fontsize= 12,loc='lower right');\n\nsns.barplot(x= 'season', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='viridis', hue='specialTeamsPlayType',alpha=.9,ax=ax14)\nax14.set_title('Play type',fontsize=16)\nax14.set_xticks([-1,0,1,2,3])\nax14.set_xticklabels(['',2018, 2019, 2020,''])\nax14.tick_params(labelsize=14)\nax14.set_ylabel('')\nax14.set_xlabel('')\nax14.legend(ncol=1,fontsize=10,title='Play type',title_fontsize= 12,loc='center left');\n\nfig.text(.5,.92, 'Avg distance ran in a play by a player',horizontalalignment='center', fontsize=18)\n\nsns.barplot(x= 'season', y= 's_mean', data= tracking_agg, ci=99.9, palette='viridis', hue='side',alpha=.9,ax=ax21)\nax21.set_title('')\nax21.set_xticks([-1,0,1,2,3])\nax21.set_xticklabels(['',2018, 2019, 2020,''])\nax21.tick_params(labelsize=14)\nax21.set_ylabel('Speed (y/s)',fontsize=14)\nax21.set_xlabel('')\nax21.legend(ncol=1,fontsize=10,title='Side',title_fontsize= 12,loc='lower right');\n\nsns.barplot(x= 'season', y= 's_mean', data= tracking_agg, ci=99.9, palette='viridis', hue='team', alpha=.9, ax=ax22)\nax22.set_title('')\nax22.set_xticks([-1,0,1,2,3])\nax22.set_xticklabels(['',2018, 2019, 2020,''])\nax22.tick_params(labelsize=14)\nax22.set_ylabel('')\nax22.set_xlabel('')\nax22.legend(ncol=1,fontsize=10,title='Team',title_fontsize= 12,loc='lower right')\n\nsns.barplot(x= 'season', y= 's_mean', data= tracking_agg, ci=99.9, palette='viridis', hue='quarter',alpha=.9,ax=ax23)\nax23.set_title('')\nax23.set_xticks([-1,0,1,2,3])\nax23.set_xticklabels(['',2018, 2019, 2020,''])\nax23.tick_params(labelsize=14)\nax23.set_ylabel('')\nax23.set_xlabel('')\nax23.legend(ncol=1,fontsize=10,title='Quarter',title_fontsize= 12,loc='lower right');\n\nsns.barplot(x= 'season', y= 's_mean', data= tracking_agg, ci=99.9, palette='viridis', hue='specialTeamsPlayType', alpha=.9, ax=ax24)\nax24.set_title('')\nax24.set_xticks([-1,0,1,2,3])\nax24.set_xticklabels(['',2018, 2019, 2020,''])\nax24.tick_params(labelsize=14)\nax24.set_ylabel('')\nax24.set_xlabel('')\nax24.legend(ncol=1,fontsize=10,title='Play type',title_fontsize= 12,loc='center left')\n\nfig.text(.5,.48, 'Avg spead of a player in a play',horizontalalignment='center', fontsize=18)\n\n\nfig.suptitle('Distance and Speed Summary', fontsize=20,y=.98);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:18:10.767644Z","iopub.execute_input":"2022-01-07T09:18:10.767974Z","iopub.status.idle":"2022-01-07T09:18:35.022815Z","shell.execute_reply.started":"2022-01-07T09:18:10.767936Z","shell.execute_reply":"2022-01-07T09:18:35.021947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(24,11))\nsns.barplot(x= 'position', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='viridis', hue='season',ax=ax1,\n            order= tracking_agg.groupby('position')['dis_sum'].mean().sort_values(ascending= False).index)\nax1.set_title('Avg of distance ran in a play given the position and sesaon',fontsize=20)\nax1.tick_params(labelsize=14)\nax1.set_ylabel('Avg Distance ran (yards)',fontsize=16)\nax1.set_xlabel('')\nax1.legend(ncol=1,fontsize=14,title='Season',title_fontsize= 14);\n\nsns.barplot(x= 'position', y= 's_mean', data= tracking_agg, ci=99.9, palette='viridis', hue='season',ax=ax2,\n            order= tracking_agg.groupby('position')['s_mean'].mean().sort_values(ascending= False).index)\nax2.set_title('Avg speed in a play given the position and sesaon',fontsize=20)\nax2.tick_params(labelsize=14)\nax2.set_ylabel('Avg speed (y/s)',fontsize=16)\nax2.set_xlabel('')\nax2.legend(ncol=1,fontsize=14,title='Season',title_fontsize= 14);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:18:35.024129Z","iopub.execute_input":"2022-01-07T09:18:35.024845Z","iopub.status.idle":"2022-01-07T09:18:45.894184Z","shell.execute_reply.started":"2022-01-07T09:18:35.024802Z","shell.execute_reply":"2022-01-07T09:18:45.893228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Using box plot to explore outliers","metadata":{}},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(24,11))\nsns.boxplot(x= 'position', y= 'dis_sum', data= tracking_agg, palette='viridis', hue='season',\n            order= tracking_agg.groupby('position')['dis_sum'].mean().sort_values(ascending= False).index,ax=ax1)\nax1.set_title('Distance ran in a play given the position and sesaon',fontsize=20)\nax1.tick_params(labelsize=14)\nax1.set_ylabel('Distance ran (yards)',fontsize=16)\nax1.set_xlabel('')\nax1.legend(ncol=1,fontsize=12,title='Season',title_fontsize= 14);\n\nsns.boxplot(x= 'position', y= 's_mean', data= tracking_agg, palette='viridis', hue='season',\n            order= tracking_agg.groupby('position')['s_mean'].mean().sort_values(ascending= False).index,ax=ax2)\nax2.set_title('Speed average in a play given the position and sesaon',fontsize=20)\nax2.tick_params(labelsize=14)\nax2.set_ylabel('Speed (y/s)',fontsize=16)\nax2.set_xlabel('')\nax2.legend(ncol=1,fontsize=12,title='Season',title_fontsize= 14);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:18:45.895936Z","iopub.execute_input":"2022-01-07T09:18:45.896275Z","iopub.status.idle":"2022-01-07T09:18:49.840044Z","shell.execute_reply.started":"2022-01-07T09:18:45.896238Z","shell.execute_reply":"2022-01-07T09:18:49.839227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> ### Seems like there are a lot of outliers","metadata":{}},{"cell_type":"markdown","source":"### Now we plot the same variables with only changing the season variable to quarters","metadata":{}},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(28,11))\nsns.boxplot(x= 'position', y= 'dis_sum', data= tracking_agg, palette='viridis', hue='quarter',\n            order= tracking_agg.groupby('position')['dis_sum'].mean().sort_values(ascending= False).index,ax=ax1)\nax1.set_title('Distance ran in a play given the position and quarter',fontsize=20)\nax1.tick_params(labelsize=14)\nax1.set_ylabel('Distance ran (yards)',fontsize=16)\nax1.set_xlabel('')\nax1.legend(ncol=1,fontsize=12,title='quarter',title_fontsize= 14);\n\nsns.boxplot(x= 'position', y= 's_mean', data= tracking_agg, palette='viridis', hue='quarter',\n            order= tracking_agg.groupby('position')['s_mean'].mean().sort_values(ascending= False).index,ax=ax2)\nax2.set_title('Speed average in a play given the position and quarter',fontsize=20)\nax2.tick_params(labelsize=14)\nax2.set_ylabel('Speed (y/s)',fontsize=16)\nax2.set_xlabel('')\nax2.legend(ncol=1,fontsize=12,title='quarter',title_fontsize= 14);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:18:49.841257Z","iopub.execute_input":"2022-01-07T09:18:49.841485Z","iopub.status.idle":"2022-01-07T09:18:55.582656Z","shell.execute_reply.started":"2022-01-07T09:18:49.841459Z","shell.execute_reply":"2022-01-07T09:18:55.582027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n","metadata":{}},{"cell_type":"markdown","source":"### Next we check teams statistics\n#### We will order the teams to focus on the last Super Bowl and Conference winners","metadata":{}},{"cell_type":"code","source":"NE = requests.get(\"https://cdn.freebiesupply.com/images/large/2x/new-england-patriots-logo-transparent.png\")\nNE = Image.open(BytesIO(NE.content))\nKC = requests.get(\"https://logos-world.net/wp-content/uploads/2020/05/Kansas-City-Chiefs-logo.png\")\nKC = Image.open(BytesIO(KC.content))\nTB = requests.get(\"https://cdn.freebiesupply.com/images/large/2x/tampa-bay-buccaneers-logo-transparent.png\")\nTB = Image.open(BytesIO(TB.content))\nSF = requests.get(\"https://assets.stickpng.com/images/580b585b2edbce24c47b2b55.png\")\nSF = Image.open(BytesIO(SF.content))\nLA = requests.get(\"https://logodownload.org/wp-content/uploads/2020/09/la-rams-logo-0.png\")\nLA = Image.open(BytesIO(LA.content))\nfinalists = [TB,KC,SF,NE,LA]\nfor i in finalists:\n    i.thumbnail((250,250))\n    LA.convert('RGBA')\nimg = Image.new('RGBA', (1250, 250), color = (255, 255, 255))\nx = 0\nfor i,j in enumerate(finalists):\n    if i not in [0,4]:\n        img.paste(j,box=(x,50))\n    else:\n        img.paste(j, box= (x,0))\n    x += 250\nfig, axeses = plt.subplots(1,5, figsize=(27,7))\n\nfor ax, logo in zip(axeses, finalists):\n    ax.imshow(logo,interpolation='nearest')\n    ax.spines['top'].set_visible(False)\n    ax.spines['left'].set_visible(False)\n    ax.spines['bottom'].set_visible(False)\n    ax.spines['right'].set_visible(False)\n    ax.set_xticks([])\n    ax.set_yticks([])\n    ax.set_facecolor('white')\nfig.suptitle(\"Finalists of the last three seasons\\n\\n\\n\",y=.95, fontsize=20)\n\naxeses[0].set_title('NFC Champion 2020\\nWon Super Bowl\\n', fontsize=16)\naxeses[1].set_title('AFC Champion 2019/2020\\nWon Super Bowl 2019 lost 2020\\n\\n\\n', fontsize=16)\naxeses[2].set_title('NFC Champion 2019\\nLost Super Bowl\\n\\n\\n', fontsize=16)\naxeses[3].set_title('AFC Champion 2018\\nWon Super Bowl\\n\\n\\n', fontsize=16)\naxeses[4].set_title('\\n\\nNFC Champion 2018\\nLost Super Bowl', fontsize=16);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:18:55.583895Z","iopub.execute_input":"2022-01-07T09:18:55.584268Z","iopub.status.idle":"2022-01-07T09:18:57.674522Z","shell.execute_reply.started":"2022-01-07T09:18:55.584228Z","shell.execute_reply":"2022-01-07T09:18:57.673649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Making an order list for teams and also divisions","metadata":{}},{"cell_type":"code","source":"team_ord = ['TB','KC','SF','NE','LA','IND','WAS','MIA',\n            'NYG','DET','NO','NYJ','CLE','MIN','HOU','TEN',\n            'CIN','GB','BUF','DEN','JAX','DAL','ARI','LAC',\n            'CHI','SEA','PIT','CAR','ATL', 'BAL','OAK','LV']\ndiv_ord = ['AFC south','NFC south','AFC east', 'NFC east',\n           'AFC north', 'NFC north', 'AFC west', 'NFC west']","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:18:57.675897Z","iopub.execute_input":"2022-01-07T09:18:57.676533Z","iopub.status.idle":"2022-01-07T09:18:57.682592Z","shell.execute_reply.started":"2022-01-07T09:18:57.676494Z","shell.execute_reply":"2022-01-07T09:18:57.681965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Let's explore distance and speed","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(28,11))\ngrid =  gridspec.GridSpec(2,6 ,figure=fig, hspace=.25,wspace=.15 )\nax1 = fig.add_subplot(grid[0, 0])\nax12 = fig.add_subplot(grid[0, 1:3])\nax13 = fig.add_subplot(grid[0, 3:])\nax2 = fig.add_subplot(grid[1, 0])\nax22 = fig.add_subplot(grid[1, 1:3])\nax23 = fig.add_subplot(grid[1, 3:])\n\nsns.barplot(x= 'team_conference', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='Blues', hue='season', ax= ax1)\nax1.set_title('Avg Distance ran in a play by a player\\ngiven team conference and sesaon',fontsize=12)\nax1.tick_params(labelsize=12)\nax1.set_ylabel('Distance (yards)',fontsize=14)\nax1.set_xlabel('')\nax1.set_ylim(0,37)\nax1.get_legend().remove()\n\nsns.barplot(x= 'team_region', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='Blues', hue='season', ax= ax12)\nax12.set_title('Avg Distance ran in a play by a player\\ngiven team region and sesaon',fontsize=12)\nax12.tick_params(labelsize=12)\n# ax12.set_yticks([])\nax12.set_ylabel('')\nax12.set_xlabel('')\nax12.set_ylim(0,37)\nax12.get_legend().remove()\n\nsns.barplot(x= 'team_division', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='Blues', hue='season', ax= ax13)\nax13.set_title('Avg Distance ran in a play by a player\\ngiven his division and sesaon',fontsize=12)\nax13.tick_params(labelsize=12)\n# ax13.set_yticks([])\nax13.set_ylabel('')\nax13.set_xlabel('')\nax13.set_ylim(0,37)\nax13.get_legend().remove()\n\n\nsns.barplot(x= 'team_conference', y= 's_mean', data= tracking_agg, ci=99.9, palette='Blues', hue='season', ax= ax2)\nax2.set_title('Avg speed of a player\\ngiven conference and sesaon',fontsize=12)\nax2.tick_params(labelsize=12)\nax2.set_ylabel('Speed (y/s)',fontsize=14)\nax2.set_xlabel('')\nax2.set_ylim(0,4.5)\nax2.get_legend().remove()\n\nsns.barplot(x= 'team_region', y= 's_mean', data= tracking_agg, ci=99.9, palette='Blues', hue='season', ax= ax22)\nax22.set_title('Avg speed of a player\\ngiven his team region and sesaon',fontsize=12)\nax22.tick_params(labelsize=12)\n# ax22.set_yticks([])\nax22.set_ylabel('')\nax22.set_xlabel('')\nax22.set_ylim(0,4.5)\nax22.get_legend().remove()\n\nsns.barplot(x= 'team_division', y= 's_mean', data= tracking_agg, ci=99.9, palette='Blues', hue='season', ax= ax23)\nax23.set_title('Avg speed of a player\\ngiven his division and sesaon',fontsize=12)\nax23.tick_params(labelsize=12)\n# ax23.set_yticks([])\nax23.set_ylabel('')\nax23.set_xlabel('')\nax23.set_ylim(0,4.5)\nax23.get_legend().remove()\nh, l = ax1.get_legend_handles_labels()\nfig.legend(h,l, ncol=3, fontsize=10,title='Season',title_fontsize= 12,bbox_to_anchor=(.57,.95))\nfig.suptitle('Distance and speed of player in each play', fontsize=20);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:18:57.68362Z","iopub.execute_input":"2022-01-07T09:18:57.684263Z","iopub.status.idle":"2022-01-07T09:19:16.445261Z","shell.execute_reply.started":"2022-01-07T09:18:57.684232Z","shell.execute_reply":"2022-01-07T09:19:16.444388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we explore by teams","metadata":{}},{"cell_type":"code","source":"fig, [ax1,ax2,ax3] = plt.subplots(3,1, figsize=(25,16))\n\nsns.barplot(x= 'team_name', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='Blues', hue='season',order= team_ord, ax= ax1)\nax1.set_title('Avg Distance ran in a play by a player given his team and the sesaon',fontsize=16)\nax1.tick_params(labelsize=12)\nax1.set_ylabel('Distance (yards)',fontsize=14)\nax1.set_xlabel('')\nax1.set_ylim(15,37)\nax1.get_legend().remove()\nsns.barplot(x= 'homeTeamAbbr', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='Blues', hue='season', order= team_ord, ax= ax2)\nax2.set_title('Avg Distance ran in a play by a player at home stadium given the team and the sesaon',fontsize=16)\nax2.tick_params(labelsize=12)\nax2.set_ylabel('Distance (yards)',fontsize=14)\nax2.set_xlabel('')\nax2.set_ylim(15,37)\nax2.get_legend().remove()\n\nsns.barplot(x= 'visitorTeamAbbr', y= 'dis_sum', data= tracking_agg, ci=99.9, palette='Blues', hue='season',order= team_ord, ax= ax3)\nax3.set_title('Avg Distance ran in a play by a player playing away given the team and the sesaon',fontsize=16)\nax3.tick_params(labelsize=12)\nax3.set_ylabel('Distance (yards)',fontsize=14)\nax3.set_xlabel('')\nax3.set_ylim(15,37)\nax3.get_legend().remove()\n\nfig.suptitle('Avg Distance covered summary by teams', y= .94, fontsize=20)\nh, l = ax1.get_legend_handles_labels()\nfig.legend(h,l, ncol=3, fontsize=14,title='Season',title_fontsize= 16,bbox_to_anchor=(.29,.93));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:16.446601Z","iopub.execute_input":"2022-01-07T09:19:16.447341Z","iopub.status.idle":"2022-01-07T09:19:33.253145Z","shell.execute_reply.started":"2022-01-07T09:19:16.447298Z","shell.execute_reply":"2022-01-07T09:19:33.252207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(24,5))\nsns.boxplot(x= 'position', y= 's_mean', data= tracking_agg, palette='viridis', hue='season',\n            order= tracking_agg.groupby('position')['s_mean'].mean().sort_values(ascending= False).index)\nplt.title('Speed average in a play given the position and sesaon',fontsize=22)\nplt.xticks(fontsize=16)\nplt.yticks(fontsize=14)\nplt.ylabel('Speed (y/s)',fontsize=16)\nplt.xlabel('')\nplt.legend(ncol=1,fontsize=12,title='Season',title_fontsize= 14);","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:33.254443Z","iopub.execute_input":"2022-01-07T09:19:33.254751Z","iopub.status.idle":"2022-01-07T09:19:35.072932Z","shell.execute_reply.started":"2022-01-07T09:19:33.254714Z","shell.execute_reply":"2022-01-07T09:19:35.072121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(18,6))\nsns.countplot(data= tracking_agg, x= 'Position', hue= 'player_is_key', palette= 'viridis');","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:19:35.074478Z","iopub.execute_input":"2022-01-07T09:19:35.075051Z","iopub.status.idle":"2022-01-07T09:19:35.989579Z","shell.execute_reply.started":"2022-01-07T09:19:35.075009Z","shell.execute_reply":"2022-01-07T09:19:35.98863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking_agg.player_is_key.value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:19:35.992529Z","iopub.execute_input":"2022-01-07T09:19:35.992772Z","iopub.status.idle":"2022-01-07T09:19:36.022294Z","shell.execute_reply.started":"2022-01-07T09:19:35.992744Z","shell.execute_reply":"2022-01-07T09:19:36.02103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='PMEDA'></a>\n\n\n<center><h1>Plotting Player Movement</h1></center>\n<h1></h1>\n<center><img src=\"https://www.reactiongifs.us/wp-content/uploads/2017/10/Time-outNFL.gif\" width='600' height=\"600\"></center>\n\n### Now let's take a time out from data analysis and focus a little on coding,\n### please note that in this part functional programming will be heavily used to come out with nice tools (functions) to plot tracking data without a lot of code repetion\n#### P.S most of code in this section is hidden for Aesthetic reasons (too many lines) so you can unhide it to show the code of each function.","metadata":{}},{"cell_type":"markdown","source":"### First we make a function called `football_field` to plot a football field","metadata":{}},{"cell_type":"code","source":"def football_field(ax):\n    \"\"\"\n    this function set the plot to look like a football field\n    input:\n    ax: an axes\n    return\n    matplotlib axes with football field drawn\n    \"\"\"\n    sns.set_style('ticks')\n    ax.set_xlabel('')\n    ax.set_ylabel('')\n    ax.grid(axis='x',zorder=1)\n    ax.xaxis.grid(linestyle='dotted',linewidth=2.5,color='white',zorder=1)\n    ax.set_facecolor('limegreen')\n    ax.set_xlim(0,120)\n    ax.set_ylim(0,53.4)\n    \n    ax.axvspan(0, 10,linestyle='', color='white', alpha=1, zorder=2)\n    ax.axvspan(110,120, linestyle='', color='white', alpha=1, zorder=2)\n    ax.axvspan(0, 10, linestyle='', color='fuchsia', alpha=.4, zorder=3)\n    ax.axvspan(110, 120, linestyle='', color='fuchsia', alpha=.4, zorder=3)\n    \n    ax.xaxis.set_major_locator(MultipleLocator(10))\n    ax.xaxis.set_major_formatter('{x:.0f}')\n    ax.xaxis.set_minor_locator(MultipleLocator(1))\n    ax.spines['top'].set_visible(False)\n    ax.spines['right'].set_visible(False)\n    ax.spines['bottom'].set_visible(False)\n    ax.spines['left'].set_visible(False)\n    \n    ax.axvline(10, color='white',linewidth=4 ,zorder=3)\n    ax.axvline(110, color='white',linewidth= 4,zorder= 3)\n    ax.axvline(60, color='white', linewidth=4,zorder=3)\n    for i in range(11,110,2):\n        ax.axvline(i,.48,.52,linewidth= 2 ,zorder=4, alpha=.9,color='white')\n    \n    ax.tick_params(axis='x', which='minor',direction ='in', top=True,bottom=True, length = 8,width= 1.5,color='white', zorder=3)\n    ax.tick_params(axis='x', which='major',direction ='in', top=True,labeltop= True,bottom=True, length = 10,width= 2.5,pad=-35,labelsize='small', color='white',labelcolor='white',zorder=3)\n    ax.tick_params(axis='y', which='major', left=False)\n    ax.set_xticks([i for i in range(0,121,10)])\n    ax.set_xticklabels(['','','1 0','2 0','3 0','4 0','5 0','4 0','3 0','2 0','1 0','',''],fontsize=22,fontfamily='serif',fontweight='heavy')\n    ax.set_yticks([])\n    return ax","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:36.024606Z","iopub.execute_input":"2022-01-07T09:19:36.025357Z","iopub.status.idle":"2022-01-07T09:19:36.039922Z","shell.execute_reply.started":"2022-01-07T09:19:36.025315Z","shell.execute_reply":"2022-01-07T09:19:36.039215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Testing the function","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(figsize=(12,5.5))\nax  = football_field(ax)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:19:36.041403Z","iopub.execute_input":"2022-01-07T09:19:36.04186Z","iopub.status.idle":"2022-01-07T09:19:37.681029Z","shell.execute_reply.started":"2022-01-07T09:19:36.041823Z","shell.execute_reply":"2022-01-07T09:19:37.680224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center><h3>Looking Good!</h3></center>","metadata":{}},{"cell_type":"markdown","source":"<center><img src=\"https://www.reactiongifs.us/wp-content/uploads/2018/11/2018-NFL-Football-1.gif\" width=600 height=500></center>","metadata":{}},{"cell_type":"markdown","source":"### The coming function is called `get_player_data` and is meant to extract players' data","metadata":{}},{"cell_type":"code","source":"def get_player_data(year, playername=None, nflid=None):\n    '''\n    this function get player data\n    input:\n    playername: string, the name of the player\n    nflid: int, unique identifier of the player\n    year int, the year which its data is being plotted\n    return:\n    player weight, height and age\n    '''\n    if playername == nflid == None:\n        print(colored('kindly enter either player name or his NFL ID','red'))\n        return None\n    if playername != None:\n        if playername not in players.displayName.values:\n            print(colored('Wrong name!, {} is not in players database you can try this with NFL ID'.format(playername),'red'))\n            return None\n        if playername in missing_players.keys():\n            weight = missing_players[playername][1]\n            height = missing_players[playername][0]\n            Age = '--'\n        elif playername in duplicated_names:\n            nflid = int(input('this name is duplicated kindly enter the nflid of the player'))\n            weight = players[players.nflId == nflid].weight.values[0]\n            height = players[players.nflId == nflid].highcm.values[0]\n            Age = players[players.nflId == nflid].age.values[0] + (year - 2018)\n        else:\n            weight = players[players.displayName == playername].weight.values[0]\n            height = players[players.displayName == playername].highcm.values[0]\n            Age = players[players.displayName == playername].age.values[0] + (year - 2018)\n        return weight, height, Age\n    if nflid != None:\n        if nflid not in players.nflId.values:\n            print(colored('Wrong NFL ID {} is not in players database, please make sure you entered the correct ID','red'))\n            return None\n        else:\n            weight = players[players.nflId == nflid].weight.values[0]\n            height = players[players.nflId == nflid].highcm.values[0]\n            Age = players[players.nflId == nflid].age.values[0] + (year - 2018)\n        return weight, height, Age","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.682597Z","iopub.execute_input":"2022-01-07T09:19:37.683056Z","iopub.status.idle":"2022-01-07T09:19:37.694581Z","shell.execute_reply.started":"2022-01-07T09:19:37.683016Z","shell.execute_reply":"2022-01-07T09:19:37.69395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we make a function called `get_game_id` to get game id","metadata":{}},{"cell_type":"code","source":"games.set_index('gameId',inplace=True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.695893Z","iopub.execute_input":"2022-01-07T09:19:37.697575Z","iopub.status.idle":"2022-01-07T09:19:37.711342Z","shell.execute_reply.started":"2022-01-07T09:19:37.697535Z","shell.execute_reply":"2022-01-07T09:19:37.71035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_game_id(season, week, hometeam= None, awayteam= None, playername= None):\n    '''\n    this function gets the unique id of a game\n    inputs:\n    year: int, the year in which the game was in\n    home/away team: strng, the home/away team in this game\n    playername: string, player name that was in this game (might need to enter unique nflId of the player)\n    return:\n    gameid: int, unique game id\n    '''\n    nflid = 0\n    try:\n        if hometeam == awayteam == playername == None:\n            print(colored('Couldn\\'t get game id!, please make sure that you enter at least one of these args [hometeam, awayteam, playername]','red'))\n            return None\n    except:\n        pass\n    \n    if season not in [2018,2019,2020]:\n        print(colored('wrong season!, please make sure that selected season is in [2018:2020]','red'))\n        return None\n    elif ((week > 17) or (week < 1)) or type(week) != int:\n        print(colored('wrong week value!, please make sure that selected week is in [1:17]','red'))\n        return None\n    try:\n        if playername in duplicated_names:\n            nflid = int(input('player name is duplicated kindly enter the unique NFL id of the player\\n'))\n            nflid = players[players.displayName == playername].nflId.values[0]\n    except:\n        print(colored('{} doesn\\'t have tracking data in {}!'.format(playername, season),'red'))\n        return None\n\n    if hometeam != None:\n        try:\n            gid = games[(games.season == season) & (games.week == week) & (games.homeTeamAbbr == hometeam)].index[0] \n            return gid\n        except:\n            print(colored('make sure you selected the right home team!','red'))\n    \n    elif awayteam != None:\n        try:\n            gid = games[(games.season == season) & (games.week == week) & (games.visitorTeamAbbr == awayteam)].index[0]\n            return gid\n        except:\n            print(colored('make sure you selected the right visitor team!','red'))\n    else:\n        if season == 2018:\n            try:\n                games_this_week =list(games[(games.season == season) & (games.week == week)].index)\n                if nflid != 0:\n                    gid = tracking2018[(tracking2018.nflId == nflid) & (tracking2018.gameId.isin(games_this_week))].gameId.values[0]\n                else:\n                    gid = tracking2018[(tracking2018.displayName == playername) & (tracking2018.gameId.isin(games_this_week))].gameId.values[0]\n                return gid\n            except:\n                 print(colored('{} doesn\\'t have tracking data in {}!'.format(playername, season),'red'))\n        elif season == 2019:\n            try:\n                games_this_week =list(games[(games.season == season) & (games.week == week)].index)\n                if nflid != 0:\n                    gid = tracking2019[(tracking2019.nflId == nflid) & (tracking2019.gameId.isin(games_this_week))].gameId.values[0]\n                else:\n                    gid = tracking2019[(tracking2019.displayName == playername) & (tracking2019.gameId.isin(games_this_week))].gameId.values[0]\n                return gid\n            except:\n                 print(colored('{} doesn\\'t have tracking data in {}!'.format(playername, season),'red'))\n        elif season == 2020:\n            try:\n                games_this_week =list(games[(games.season == season) & (games.week == week)].index)\n                if nflid != 0:\n                    gid = tracking2020[(tracking2020.nflId == nflid) & (tracking2020.gameId.isin(games_this_week))].gameId.values[0]\n                else:\n                    gid = tracking2020[(tracking2020.displayName == playername) & (tracking2020.gameId.isin(games_this_week))].gameId.values[0]\n                return gid\n            except:\n                 print(colored('{} doesn\\'t have tracking data in {}!'.format(playername, season),'red'))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.712914Z","iopub.execute_input":"2022-01-07T09:19:37.713196Z","iopub.status.idle":"2022-01-07T09:19:37.731146Z","shell.execute_reply.started":"2022-01-07T09:19:37.71317Z","shell.execute_reply":"2022-01-07T09:19:37.730537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we make some functions to get specific games' id's to that end we will make these functions:\n* `get_team_games`\n* `get_player_games`","metadata":{}},{"cell_type":"code","source":"def get_team_games(team, season=0, where= 'all'):\n    '''\n    this function returns all games id's for a team\n    team: string, team name for which games id's are being extracted\n    season: int, the season on which games were played if let it will exrtact all games in all season in the database\n    where: string, extract games only playing in home, away or both\n    return:\n    team_games: list containt games id's\n    '''\n    if team not in team_abb.keys():\n        print(colored('Wrong team name! cold\\'nt find values for `{}`'.format(team),'red'))\n        return None\n    \n    if where not in ['home', 'away', 'all']:\n        print(colored('Wrong value for `where` arg!, please make sure it\\'s within [home, away, all]','red'))\n        return None\n    \n    elif season == 0:\n        if where == 'all':\n            team_games = list(games[(games.homeTeamAbbr == team) | (games.visitorTeamAbbr == team)].index)\n        elif where == 'home':\n            team_games = list(games[games.homeTeamAbbr == team].index)\n        elif where == 'away':\n            team_games = list(games[games.visitorTeamAbbr == team].index)\n        return team_games\n    \n    elif season not in [2018, 2019, 2020]:\n        print(colored('Wrong season! please make sure that season is in [2018:2020] period','red'))\n        return None\n    \n    else:\n        if where == 'all':\n            team_games = list(games[(games.season == season) & ((games.homeTeamAbbr == team) | (games.visitorTeamAbbr == team))].index)\n        elif where == 'home':\n            team_games = list(games[(games.season == season) & (games.homeTeamAbbr == team)].index)\n        elif where == 'away':\n            team_games = list(games[(games.season == season) & (games.visitorTeamAbbr == team)].index)      \n        return team_games\n    ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.732314Z","iopub.execute_input":"2022-01-07T09:19:37.732664Z","iopub.status.idle":"2022-01-07T09:19:37.745001Z","shell.execute_reply.started":"2022-01-07T09:19:37.732627Z","shell.execute_reply":"2022-01-07T09:19:37.744432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_player_games(season, playername= None, nflid= None, where= 'all'):\n    '''\n    this function returns all games id's for a players\n    playername: string, player name for which games id's are being extracted\n    season: int, the season on which games were played if let it will exrtact all games in all season in the database\n    where: string, extract games only playing in home, away or both\n    return:\n    team_games: list containt games id's\n    '''\n    if playername == nflid == None:\n        print(colored('kindly enter either player name or his NFL ID','red'))\n        return None\n    if where not in ['home', 'away', 'all']:\n        print(colored('Wrong value for `where` arg!, please make sure it\\'s within [home, away, all]','red'))\n        return None\n    tracking = eval('tracking'+str(season))\n    if playername != None:\n        if playername in duplicated_names:\n            nflid = int(input('this name is duplicated kindly enter the nflid of the player'))\n            if where == 'all':\n                player_games = list(tracking[tracking.nflId == nflid].gameId.unique())\n            elif where == 'home':\n                player_games = list(tracking[(tracking.nflId == nflid) & (tracking.team == 'home')].gameId.unique())\n            elif where =='away':\n                player_games = list(tracking[(tracking.nflId == nflid) & (tracking.team == 'away')].gameId.unique())\n        else:\n            if where == 'all':\n                player_games = list(tracking[tracking.displayName == playername].gameId.unique())\n            elif where == 'home':\n                player_games = list(tracking[(tracking.displayName == playername) & (tracking.team == 'home')].gameId.unique())\n            elif where =='away':\n                player_games = list(tracking[(tracking.displayName == playername) & (tracking.team == 'away')].gameId.unique())\n        \n    elif nflid != None:\n        if nflid not in players.nflId.values:\n            print(colored('Wrong NFL ID {} is not in players database, please make sure you entered the correct ID','red'))\n            return None\n        else:\n            if where == 'all':\n                player_games = list(tracking[tracking.nflId == nflid].gameId.unique())\n            elif where == 'home':\n                player_games = list(tracking[(tracking.nflId == nflid) & (tracking.team == 'home')].gameId.unique())\n            elif where =='away':\n                player_games = list(tracking[(tracking.nflId == nflid) & (tracking.team == 'away')].gameId.unique())\n    del tracking\n    return player_games","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.74638Z","iopub.execute_input":"2022-01-07T09:19:37.746966Z","iopub.status.idle":"2022-01-07T09:19:37.760078Z","shell.execute_reply.started":"2022-01-07T09:19:37.746938Z","shell.execute_reply":"2022-01-07T09:19:37.75951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### This coming function is called `get_plays` and is meant to get plays within a game","metadata":{}},{"cell_type":"code","source":"def get_plays(gameid, posteam= None):\n    '''\n    this function print all plays within a game\n    inputs:\n    gameid: int, unique identifier of a game\n    posteam: string, optional, name of the team that possesses the ball\n    return:\n    list of all plays within a game\n    '''\n    if posteam == None:\n        plays_list = list(plays[plays.gameId == gameid].playId)\n        if len(plays_list) == 0:\n            print(colored('make sure that you insert the correct values','red'))\n            return\n        else:\n            return plays_list\n    else:\n        plays_list = list(plays[(plays.gameId == gameid) & (plays.possessionTeam == posteam)].playId)\n        if len(plays_list) == 0:\n            print(colored('Make sure that you insert the correct values!','red'))\n            return\n        else:\n            return plays_list","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.7614Z","iopub.execute_input":"2022-01-07T09:19:37.762035Z","iopub.status.idle":"2022-01-07T09:19:37.774376Z","shell.execute_reply.started":"2022-01-07T09:19:37.762001Z","shell.execute_reply":"2022-01-07T09:19:37.773734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### As the name suggest `get_play_data` is meant to extract data about a play","metadata":{}},{"cell_type":"code","source":"def get_play_data(df, gameid, playid):\n    '''\n    this function gets a single play data\n    input:\n    df: dataFrame, sub tracking dataFrame to extract data from\n    gameid int, unique identifier of a game\n    return\n    week, date, home, away, posteam, team, direction, gtype, and result of the play\n    '''\n    week = games.loc[gameid,'week']\n    date = games.loc[gameid,'gameDate']\n    home = games.loc[gameid,'homeTeamAbbr']\n    away = games.loc[gameid,'visitorTeamAbbr']\n    posteam = plays[(plays.gameId == gameid) & (plays.playId == playid)].possessionTeam.values[0]\n    team = df['team'].values[0]\n    posteam = plays[(plays.gameId == gameid) & (plays.playId == playid)].possessionTeam.values[0]\n    direction = df['playDirection'].values[0]\n    gtype = plays[(plays.gameId == gameid) & (plays.playId == playid)].specialTeamsPlayType.values[0]\n    result = plays[(plays.gameId == gameid) & (plays.playId == playid)].specialTeamsResult.values[0]\n    return week, date, home, away, posteam, team, direction, gtype, result","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.775702Z","iopub.execute_input":"2022-01-07T09:19:37.775925Z","iopub.status.idle":"2022-01-07T09:19:37.786326Z","shell.execute_reply.started":"2022-01-07T09:19:37.7759Z","shell.execute_reply":"2022-01-07T09:19:37.785543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### The next function is called `plot_custom` and it use past functions to comout with a plot ","metadata":{}},{"cell_type":"code","source":"def plot_custom(df, playername, year, gameid=None, playid=None, ball= False):\n    \"\"\"\n    this is the main plotting func, it plots player movmement and heat map of that movment\n    inputs:\n    df: sub-dataframe to plot from, extracted from tracking2018\n    playrname: string, player we are try to plot his movement\n    year: int, year in whic tracking is in\n    ball: bool, boolean to plot the ball \n    return:\n    figure of player movement with direction, ball movment (if plotting a single play) and also heat map of player movment\n    \"\"\"\n    sns.set_style('ticks')\n    if ball == True:\n        g_ball_df = eval('ball_'+str(year)[-2:]+'_df')\n        if (gameid != None) and (playid == None):\n            g_ball_df = g_ball_df[g_ball_df.gameId == gameid]\n        elif (gameid != None) and (playid != None):\n            g_ball_df = g_ball_df[(g_ball_df.gameId == gameid) & (g_ball_df.playId == playid)]\n    fig = plt.figure(figsize=(1.2*25,1.2*5.5))\n    plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=.02,hspace=.2)\n    ax = fig.add_subplot(1,2,1)\n    ax2 = fig.add_subplot(1,2,2)\n    ax = football_field(ax)\n    ax2 = football_field(ax2)\n    sns.kdeplot(x='x', y='y', data= df, cmap= hcmap,fill=True,alpha=.85,ax=ax,zorder=5)\n    ax2.quiver(df.x, df.y, df.x, df.y,angles= (90- df.dir ), zorder=5, pivot=\"mid\",edgecolor='none',color='blue',alpha=.3,headwidth = 7 )\n    if ball == True:\n        ax2.scatter(g_ball_df.x, g_ball_df.y ,color='brown', alpha=.7, marker=\"o\", s= 80, label='Ball', zorder=6)\n        ax2.legend(loc='upper right')\n    weight, height, Age = get_player_data(year,playername)\n    fig.suptitle('Plotting {} Movement\\nAge:{} yrs | Weight: {} lb | Height: {} cm'.format(playername,Age,weight,height),fontsize=16)\n    ax.set_title('Heat map of {} movment'.format(playername),fontsize=16)\n    ax2.set_title('Movement and direction of {}'.format(playername),fontsize=16)\n    if playid != None:\n        p_week, p_date, p_home, p_away, p_posteam, p_team, p_direction, p_gtype, p_result = get_play_data(df, gameid= gameid, playid= playid)\n        boxstr = 'Week:{}\\nOn: {}\\nHome: {}\\nAway: {}\\nPlayer is in {}\\n{}\\'s ball\\nType: {}\\nResult: {}'.format(p_week, p_date,\n                                                                                                                 p_home , p_away, p_team,\n                                                                                                                 p_posteam, p_gtype, p_result)\n        fig.text(.49,.45,boxstr, fontsize=12, bbox=dict(boxstyle=\"round\",ec='white',fc='lightgrey',alpha=.9),ha=\"left\", va=\"center\")\n        if p_direction == 'right':\n            fig.text(.49,.65, 'Play direction', fontsize=14, bbox=dict(boxstyle=\"rarrow\",ec='orange',fc='orange',alpha=.9),ha=\"left\", va=\"center\")\n        else:\n            fig.text(.49,.65, 'Play direction', fontsize=14, bbox=dict(boxstyle=\"larrow\",ec='orange',fc='orange',alpha=.9),ha=\"left\", va=\"center\")\n    ax.set_xlabel('')\n    ax2.set_xlabel('')\n    return fig;","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.789521Z","iopub.execute_input":"2022-01-07T09:19:37.790383Z","iopub.status.idle":"2022-01-07T09:19:37.80558Z","shell.execute_reply.started":"2022-01-07T09:19:37.790353Z","shell.execute_reply":"2022-01-07T09:19:37.804774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we reached the main function which is called `plot_player_mvt`  this function uses the previous functions to plot both player movement with direction, ball movment (if plotting a single play) and also heat map of player movment","metadata":{}},{"cell_type":"code","source":"def plot_player_mvt(playername, season, week = None, playid= None, ball= False):\n    '''\n    plots player movements as scatter and heatmap in a whole year\n    inputs:\n    playername: string, the name of the player\n    year: int (maybe required promptly), year in which tracking data was recorded\n    week: the game week if it's required to plot only movement in a single game\n    play: the play id if it's required to only plot a single play movements\n    ball: bool, boolean to plot the ball used only when plotting a game or a play\n    return:\n    heatmap and scatter plots of a player's movement in a whole year\n    '''\n    seasons = [2018,2019,2020]\n    if season not in seasons:\n        while True:\n            print(colored('Please make sure that selected season is in [2018:2020]','red'))\n            season = input('Please select the year in which player\\'s tracking data was in, kindly select one of the following\\n1 for 2018\\n2 for 2019\\n3 for 2020\\n4 to exit\\n')\n            if season in ['1','2','3']:\n                season = int(season) + 2017\n                break\n            elif season == '4':\n                return None;\n            else:\n                print('kindly enter one of the above mentioned options!')\n\n    if week != None:\n        while True:\n            if ((week > 17) or (week < 1)) or type(week) != int:\n                print(colored('wrong week value!, please make sure that selected week is in [1:17]','red'))\n                week = int(input('kindly insert week again:\\n'))\n            else:\n                gameid = get_game_id(season, week, playername= playername)\n                player_games = get_player_games(season,playername)\n                if (gameid not in player_games) or (player_games == None):\n                    print(colored('{} didn\\'t play in this week/season'.format(season),'red'))\n                    return None\n                else:\n                    break\n   \n    temp_tracking = eval('tracking'+str(season))\n    if (week != None) and (playid != None):\n        if playername in duplicated_names:\n            nflid = int(input('this name is duplicated kindly enter the nflid of the player'))\n            temp_df = temp_tracking[(temp_tracking.gameId == gameid) & (temp_tracking.nflId == nflid) & (temp_tracking.playId == playid)]\n        else:\n            temp_df = temp_tracking[(temp_tracking.gameId == gameid) & (temp_tracking.displayName == playername) & (temp_tracking.playId == playid)]\n        if len(temp_df) == 0:\n            print(colored(playername +' doesn\\'t have tracking data in {} week {} play no. {}!'.format(season, week, playid),'red'))\n            return None;\n        fig = plot_custom(temp_df, playername, year= season, gameid= gameid, playid= playid, ball= ball)\n        del temp_tracking, temp_df\n        gc.collect()\n    elif week !=None:\n        if playername in duplicated_names:\n            nflid = int(input('this name is duplicated kindly enter the nflid of the player'))\n            temp_df = temp_tracking[(temp_tracking.gameId == gameid) & (temp_tracking.nflId == nflid)]\n        else:\n            temp_df = temp_tracking[(temp_tracking.gameId == gameid) & (temp_tracking.displayName == playername)]\n        if len(temp_df) == 0:\n            print(colored(playername +' doesn\\'t have tracking data in {} week {}!'.format(season, week),'red'))\n            return None;\n        fig = plot_custom(temp_df, playername, year= season, gameid= gameid, ball= ball)\n        del temp_tracking, temp_df\n        gc.collect()\n    else:\n        if playername in duplicated_names:\n            nflid = int(input('this name is duplicated kindly enter the nflid of the player'))\n            temp_df = temp_tracking[temp_tracking.nflId == nflid]\n        else:\n            temp_df = temp_tracking[temp_tracking.displayName == playername]\n        if len(temp_df) == 0:\n            print(colored(playername +' doesn\\'t have tracking data in {} season!'.format(season),'red'))\n            return None;\n        temp_df = temp_tracking[temp_tracking.displayName == playername]\n        fig = plot_custom(temp_df, playername, year= season, ball= ball)\n        del temp_tracking, temp_df\n        gc.collect()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.807286Z","iopub.execute_input":"2022-01-07T09:19:37.807727Z","iopub.status.idle":"2022-01-07T09:19:37.824637Z","shell.execute_reply.started":"2022-01-07T09:19:37.807697Z","shell.execute_reply":"2022-01-07T09:19:37.82388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now lets make an animation function called `plot_play` that make a video animation of a play with all players and also the ball ","metadata":{}},{"cell_type":"code","source":"def plot_play(season, gameid, playid):\n    \"\"\"\n    this function plot an animation of a whole play including all players\n    inputs:\n    gameid: unique game identifier\n    playid: unique play identifier\n    return:\n    an animation of a play\n    \"\"\"\n    fig, ax = plt.subplots(figsize=(1.2*(12),1.2*(5.4)))\n    plt.rcParams[\"animation.html\"] = \"jshtml\"\n    tracking = eval('tracking'+str(season))\n    eball = eval('ball_'+str(season)[-2:]+'_df')\n    temp_tr = tracking[(tracking.playId ==playid) & (tracking.gameId == gameid)].set_index(['time','frameId' ]).sort_index()\n    temp_ball = eball[(eball.playId ==playid) & (eball.gameId == gameid)].set_index(['time','frameId']).sort_index()\n    frames = temp_ball.index                                                                \n\n    pos_team =  plays[(plays.gameId == gameid) & (plays.playId == playid)].possessionTeam.values[0]\n    home = games.loc[gameid,'homeTeamAbbr']\n    away = games.loc[gameid,'visitorTeamAbbr']\n    gtype = plays[(plays.gameId == gameid) & (plays.playId == playid)].specialTeamsPlayType.values[0]\n    result = plays[(plays.gameId == gameid) & (plays.playId == playid)].specialTeamsResult.values[0]\n    week = games.loc[gameid,'week']\n    ax = football_field(ax)\n    if home == pos_team:\n        Att, Def = home, away\n        temp_att = temp_tr[temp_tr.team == 'home']\n        temp_def = temp_tr[temp_tr.team == 'away'] \n    else:\n        Att, Def = away, home\n        temp_def = temp_tr[temp_tr.team == 'home']\n        temp_att = temp_tr[temp_tr.team == 'away'] \n    \n    def animate(f):\n        plt.cla()    \n        ax = plt.gca()\n        temp_ball_s = temp_ball.loc[f,:]\n        ax.scatter(temp_ball_s.x, temp_ball_s.y, color='brown', alpha=1, s=220,zorder=8, label='Ball')\n        temp_att_s = temp_att.loc[f,:]\n        temp_def_s = temp_def.loc[f,:]\n        ax.quiver(temp_att_s.x, temp_att_s.y, temp_att_s.x, temp_att_s.y, zorder=5, angles= (90- temp_att_s.dir ),\n                  pivot=\"mid\",edgecolor='none', color='red',alpha=.6,headwidth = 7, label= 'Att' )\n        ax.quiver(temp_def_s.x, temp_def_s.y, temp_def_s.x, temp_def_s.y, zorder=5, angles= (90- temp_def_s.dir ),\n                  pivot=\"mid\",edgecolor='none', color='blue',alpha=.6,headwidth = 7,  label= 'Def')\n        ax = football_field(ax)\n        ax.text(0,.96,str(f[0]),fontsize=14, bbox=dict(boxstyle=\"round\",ec='white',fc='white',alpha=.7),ha=\"left\", va=\"center\")\n        ax.set_title('Game  {} | {} vs. {} | Ball with {}\\nPlay type: {} | Result: {}'.format(week, home, away, pos_team, gtype, result),fontsize=18)\n        ax.legend(loc= 'upper right',fontsize= 13,ncol=1)\n        print('█',end='')     \n    ani = matplotlib.animation.FuncAnimation(fig, animate, frames= frames,blit=False)\n    html = HTML(ani.to_jshtml())\n    display(html)\n    plt.close()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-07T09:19:37.826194Z","iopub.execute_input":"2022-01-07T09:19:37.826428Z","iopub.status.idle":"2022-01-07T09:19:37.843392Z","shell.execute_reply.started":"2022-01-07T09:19:37.826403Z","shell.execute_reply":"2022-01-07T09:19:37.842723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_player_mvt('Keishawn Bierria',2018)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:19:37.844537Z","iopub.execute_input":"2022-01-07T09:19:37.845321Z","iopub.status.idle":"2022-01-07T09:20:05.704297Z","shell.execute_reply.started":"2022-01-07T09:19:37.845282Z","shell.execute_reply":"2022-01-07T09:20:05.703439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_player_mvt('Keishawn Bierria', 2019, week=17)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:20:05.705476Z","iopub.execute_input":"2022-01-07T09:20:05.705706Z","iopub.status.idle":"2022-01-07T09:20:12.000139Z","shell.execute_reply.started":"2022-01-07T09:20:05.705679Z","shell.execute_reply":"2022-01-07T09:20:11.999245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_player_mvt('Keishawn Bierria', 2019, week=17,playid=36, ball= True)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:20:12.001416Z","iopub.execute_input":"2022-01-07T09:20:12.001644Z","iopub.status.idle":"2022-01-07T09:20:17.200426Z","shell.execute_reply.started":"2022-01-07T09:20:12.001619Z","shell.execute_reply":"2022-01-07T09:20:17.199544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_player_mvt('Keishawn Bierria',2020)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:20:17.201664Z","iopub.execute_input":"2022-01-07T09:20:17.201887Z","iopub.status.idle":"2022-01-07T09:20:17.912903Z","shell.execute_reply.started":"2022-01-07T09:20:17.201862Z","shell.execute_reply":"2022-01-07T09:20:17.911865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Testing the animation function","metadata":{}},{"cell_type":"markdown","source":"### First we get a list of all New York Giantshome games ","metadata":{}},{"cell_type":"code","source":"nyg_home_games = get_team_games('NYG',season=2018, where='home')","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:20:17.91483Z","iopub.execute_input":"2022-01-07T09:20:17.915281Z","iopub.status.idle":"2022-01-07T09:20:17.92571Z","shell.execute_reply.started":"2022-01-07T09:20:17.915146Z","shell.execute_reply":"2022-01-07T09:20:17.925123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting plays in the first game where possession is with the Giants","metadata":{}},{"cell_type":"code","source":"giants_plays = get_plays(nyg_home_games[0],posteam='NYG')","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:20:17.927216Z","iopub.execute_input":"2022-01-07T09:20:17.92771Z","iopub.status.idle":"2022-01-07T09:20:17.937147Z","shell.execute_reply.started":"2022-01-07T09:20:17.927672Z","shell.execute_reply":"2022-01-07T09:20:17.936157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_play(2018, nyg_home_games[0], giants_plays[0])","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:20:17.938284Z","iopub.execute_input":"2022-01-07T09:20:17.938848Z","iopub.status.idle":"2022-01-07T09:21:53.512882Z","shell.execute_reply.started":"2022-01-07T09:20:17.938804Z","shell.execute_reply":"2022-01-07T09:21:53.511883Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_play(2018, 2018090906, 3527)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:21:53.514893Z","iopub.execute_input":"2022-01-07T09:21:53.515257Z","iopub.status.idle":"2022-01-07T09:22:42.846065Z","shell.execute_reply.started":"2022-01-07T09:21:53.51521Z","shell.execute_reply":"2022-01-07T09:22:42.844934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='ml'></a>\n\n# Machine learning starter\n\n### This part is just a ML playground to explore some features importance\n","metadata":{}},{"cell_type":"markdown","source":"### First we make some aggregation by each play but we will separate the offensive from the defensive sides","metadata":{}},{"cell_type":"code","source":"trackking_plays_agg = tracking_agg.groupby(['gameId','playId','side',\n                      'specialTeamsPlayType',\n                      'month','yards_to_endzone',\n                      'yardsToGo', 'down','quarter',\n                      'gameClock','pos_score_def','specialTeamsResult']).agg({'TAVG': 'mean','highcm': 'mean', 'age': 'mean','weight':'mean'}).reset_index()\ntrackking_plays_agg.gameClock = trackking_plays_agg.gameClock.apply(lambda x: round((int(x[:2]) + (int(x[3:5]) /60)),3)) \ntrackking_plays_agg.sample(8)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:22:42.847771Z","iopub.execute_input":"2022-01-07T09:22:42.848124Z","iopub.status.idle":"2022-01-07T09:22:43.281185Z","shell.execute_reply.started":"2022-01-07T09:22:42.848067Z","shell.execute_reply":"2022-01-07T09:22:43.280302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Now we split and make a function to\n- train the model\n- show training and test metrics\n- show features importance\n- plot confusion matrix","metadata":{}},{"cell_type":"code","source":"X = pd.get_dummies(trackking_plays_agg[(trackking_plays_agg['side'] == 'offense') & (trackking_plays_agg['specialTeamsPlayType'] == 'Punt')][[ 'month',\n       'yards_to_endzone', 'yardsToGo', 'down', 'quarter', 'gameClock',\n       'pos_score_def','TAVG', 'highcm', 'age', 'weight']])\ny = trackking_plays_agg[(trackking_plays_agg['side'] == 'offense') & (trackking_plays_agg['specialTeamsPlayType'] == 'Punt')]['specialTeamsResult']","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:22:43.284177Z","iopub.execute_input":"2022-01-07T09:22:43.284492Z","iopub.status.idle":"2022-01-07T09:22:43.312295Z","shell.execute_reply.started":"2022-01-07T09:22:43.284462Z","shell.execute_reply":"2022-01-07T09:22:43.311631Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = split(X, y, test_size=0.33, random_state=42)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:22:43.313264Z","iopub.execute_input":"2022-01-07T09:22:43.314018Z","iopub.status.idle":"2022-01-07T09:22:43.321585Z","shell.execute_reply.started":"2022-01-07T09:22:43.313988Z","shell.execute_reply":"2022-01-07T09:22:43.320616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_model(model, x_tr, y_tr,  x_ts, y_ts):\n    model.fit(x_tr, y_tr)\n    pred = model.predict(x_tr)\n    print('train scores\\naccuracy: ',accuracy_score(y_tr, pred),\n      '\\nprecision: ',precision_score(y_tr, pred, average='weighted'),\n      '\\nrecall: ',recall_score(y_tr, pred, average='weighted'),\n      '\\nf1: ',f1_score(y_tr, pred, average='weighted'))\n    predt = model.predict(x_ts)\n    print('test scores\\naccuracy: ',accuracy_score(y_ts, predt),\n      '\\nprecision: ',precision_score(y_ts, predt, average='weighted'),\n      '\\nrecall: ',recall_score(y_ts, predt, average='weighted'),\n      '\\nf1: ',f1_score(y_ts, predt, average='weighted'))\n    contr = confusion_matrix(pred, y_tr)\n    conts = confusion_matrix(predt, y_ts)\n    classeS = list(model.classes_)\n    fig, (ax1 ,ax2) = plt.subplots(1,2, figsize= (24,8))\n    plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=.1)\n    sns.heatmap( contr, cbar=False, annot= True,fmt='1.0f',cmap='magma_r',  ax=ax1)\n    ax1.set_xlabel('Predictied', fontsize=14)\n    ax1.set_xticklabels(classeS,rotation=345)\n    ax1.set_ylabel('Actual', fontsize=14)\n    sns.heatmap(conts, cbar=False, annot= True,fmt='1.0f',cmap='magma_r', ax=ax2)\n    ax2.set_xlabel('Predictied', fontsize=14)\n    ax2.set_ylabel('Actual', fontsize=14)\n    ax2.set_xticklabels(classeS,rotation=345)\n    ax1.set_title('Train confusion matrix', fontsize=14)\n    ax2.set_title('Test confusion matrix', fontsize=14)\n    imp= pd.DataFrame(model.feature_importances_, index= X_train.columns ,columns=('imp',))\n    print(imp.imp.sort_values(ascending = False))","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:22:43.32308Z","iopub.execute_input":"2022-01-07T09:22:43.323515Z","iopub.status.idle":"2022-01-07T09:22:43.337525Z","shell.execute_reply.started":"2022-01-07T09:22:43.323471Z","shell.execute_reply":"2022-01-07T09:22:43.336573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"xgbclf= xgb.XGBClassifier(booster='gbtree', colsample_bylevel=1,\n              colsample_bynode=1, colsample_bytree=1, eval_metric='merror',\n              gamma=1,importance_type='gain',learning_rate=0.05,max_depth=4,n_estimators=600, n_jobs=4,\n              objective='multi:softprob', random_state=0,reg_alpha=1, reg_lambda=1,tree_method='exact')\nplot_model(xgbclf,X_train,y_train, X_test, y_test)","metadata":{"execution":{"iopub.status.busy":"2022-01-07T09:22:43.338734Z","iopub.execute_input":"2022-01-07T09:22:43.33897Z","iopub.status.idle":"2022-01-07T09:22:52.65906Z","shell.execute_reply.started":"2022-01-07T09:22:43.338946Z","shell.execute_reply":"2022-01-07T09:22:52.658168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<center><img src=\"https://media4.giphy.com/media/q9TdZOZfsSspi/giphy.gif\"></center>","metadata":{}},{"cell_type":"markdown","source":"### Not Much out there but as expected yards to end zone is importat feature ","metadata":{}},{"cell_type":"markdown","source":"<h2><center><font color='red'>Upvote this or Chuck will pay you a visit..</font></center></h2>\n<center><img src=\"https://i.imgur.com/lDkgwsV.gif\"></center>","metadata":{}}]}