{"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":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\npd.set_option('display.max_columns', 5000)\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nmpl.rcParams['figure.figsize'] = (15,11)\nimport seaborn as sns\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-04T13:56:05.953893Z","iopub.execute_input":"2021-12-04T13:56:05.954296Z","iopub.status.idle":"2021-12-04T13:56:05.965779Z","shell.execute_reply.started":"2021-12-04T13:56:05.954257Z","shell.execute_reply":"2021-12-04T13:56:05.964802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"games = pd.read_csv('../input/nfl-big-data-bowl-2022/games.csv')\ngames","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:05.967770Z","iopub.execute_input":"2021-12-04T13:56:05.968052Z","iopub.status.idle":"2021-12-04T13:56:05.996469Z","shell.execute_reply.started":"2021-12-04T13:56:05.968015Z","shell.execute_reply":"2021-12-04T13:56:05.995426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"players_original = pd.read_csv('../input/nfl-big-data-bowl-2022/players.csv')\nplayers = players_original.copy()\nplayers","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:05.998356Z","iopub.execute_input":"2021-12-04T13:56:05.998705Z","iopub.status.idle":"2021-12-04T13:56:06.028321Z","shell.execute_reply.started":"2021-12-04T13:56:05.998657Z","shell.execute_reply":"2021-12-04T13:56:06.027537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"TOC\n* [Adding the plays data](#adding-plays)\n* [Adding number of returns, kicks, and blocks](#adding-number-cols)\n* [Part 1: Punters](#punters)\n* * Punters dataset includes the number of punts, ratio of normal punts (as opposed to Aussie-style), ratios of how the ball lands, ratio of punts going the intended direction, average and maximum hang times\n* [Part 2: Kickers](#kickers)\n* * Kickers dataset includes number of kickoffs and field goals, mean and max kickoff distance, mean and max kickoff hangtime, ratio of kicks going the intended direction, ratio of touchbacks, ratio of kicks that go Out of Bounds, ratio of onside kicks (to normal kicks), recovery rate of those onside kicks, mean and max distance of succesful field goals, mean, minimum and max distance of missed field goals, as well as the number of kicks made and missed in the clutch - to take the lead or tie with under 3 minutes to play\n* [Part 3: Returners](#returners)\n","metadata":{}},{"cell_type":"markdown","source":"<a id='top'></a>\n\n# Augmenting the NFL players special teams dataset\nIn this notebook, I'm going to be using the data provided in the NFL big data bowl to add a ton of features to the special teams dataset. This is currently a work-in-progress but I'll upload versions of the dataset(s) to kaggle as I go.\n\nThe current version (first one) splits the players into 3 - punters, kickers, and returners - and simply has the number of kicks, punts, whatever-they-do as an extra column. I'm planning next on connecting it with the tracking and scouting data to get some more interesting fields.\n\nFor the moment, the dataset contains several self-evident fields:\n* Player's NFL ID, a unique identifier;\n* Height, Weight, Birthdate;\n* Their college;\n* Their (non special teams) position;\n* Their name.\n\nRight off the bat, we can get some information. For example, a look at the players by college:","metadata":{}},{"cell_type":"code","source":"top25_colleges = players.groupby('collegeName').count().sort_values(by='nflId', ascending=False)['nflId'].head(25)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:06.030212Z","iopub.execute_input":"2021-12-04T13:56:06.030603Z","iopub.status.idle":"2021-12-04T13:56:06.046001Z","shell.execute_reply.started":"2021-12-04T13:56:06.030570Z","shell.execute_reply":"2021-12-04T13:56:06.044990Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# barchart of player colleges\ntop25_colleges.plot(kind='bar')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:06.047577Z","iopub.execute_input":"2021-12-04T13:56:06.049241Z","iopub.status.idle":"2021-12-04T13:56:06.635186Z","shell.execute_reply.started":"2021-12-04T13:56:06.049123Z","shell.execute_reply":"2021-12-04T13:56:06.634109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"And by position:","metadata":{}},{"cell_type":"code","source":"positions = players.groupby('Position').count().sort_values(by='nflId', ascending=False)['nflId']\n\n# barchart of positions\npositions.plot(kind='bar')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:06.636738Z","iopub.execute_input":"2021-12-04T13:56:06.637303Z","iopub.status.idle":"2021-12-04T13:56:07.236823Z","shell.execute_reply.started":"2021-12-04T13:56:06.637267Z","shell.execute_reply":"2021-12-04T13:56:07.236034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The purpose of this notebook will be to combine much of the other data supplied by the NFL into a new players dataset to facilitate this kind of analysis. ","metadata":{}},{"cell_type":"markdown","source":"### Bringing in plays data\n[Return to top](#top)\n\n<a id=\"adding-plays\"></a>\n\nThe plays data will be the first thing I'm going to use to add the number of each type of play that each players was involved with. \n\n* First, the kickerId column needs to be adjusted so that I can differentiate between a punt, kickoff and field goal;\n* Second, the returner column poses a slight problem for plays where there was a lateral involved. This will be handled in [Part 4: returners](id='returners');","metadata":{}},{"cell_type":"code","source":"plays = pd.read_csv('../input/nfl-big-data-bowl-2022/plays.csv')\nplays","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:07.238678Z","iopub.execute_input":"2021-12-04T13:56:07.238978Z","iopub.status.idle":"2021-12-04T13:56:07.427807Z","shell.execute_reply.started":"2021-12-04T13:56:07.238929Z","shell.execute_reply":"2021-12-04T13:56:07.426808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plays.info()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:07.429320Z","iopub.execute_input":"2021-12-04T13:56:07.429580Z","iopub.status.idle":"2021-12-04T13:56:07.464534Z","shell.execute_reply.started":"2021-12-04T13:56:07.429547Z","shell.execute_reply":"2021-12-04T13:56:07.463507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Splitting kickoffs, punts and field goals - I'll make a new dataframe with only some relevant info and then adjust it so that instead of a single kickerId column, it'll be punter, kickoff kicker, or fg kicker. ","metadata":{}},{"cell_type":"code","source":"kick_plays = plays.loc[plays['specialTeamsPlayType'].isin(['Kickoff', 'Punt', \"Field Goal\"])]\nkick_plays","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:07.469057Z","iopub.execute_input":"2021-12-04T13:56:07.469829Z","iopub.status.idle":"2021-12-04T13:56:07.523756Z","shell.execute_reply.started":"2021-12-04T13:56:07.469792Z","shell.execute_reply":"2021-12-04T13:56:07.522809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# drop unecessary fields\nkick_plays = kick_plays.drop(['playDescription',\n                              'quarter','down',\t'yardsToGo','possessionTeam',\n                              'specialTeamsResult', 'yardlineSide','yardlineNumber',\n                              'gameClock',\t'penaltyCodes',\t'penaltyJerseyNumbers',\n                              'penaltyYards','preSnapHomeScore', 'preSnapVisitorScore','passResult',\n                              'kickLength','kickReturnYardage', 'playResult','absoluteYardlineNumber'],\n                             axis=1)\n\n# add the new columns\nkick_plays['ko_kickerId'] = np.nan\nkick_plays['fg_kickerId'] = np.nan\nkick_plays['punterId'] = np.nan\n\n# fill the new columns \nfor row in kick_plays.itertuples():\n    if row.specialTeamsPlayType == \"Kickoff\":\n        kick_plays.at[row.Index,'ko_kickerId'] = kick_plays.at[row.Index,'kickerId']\n    elif row.specialTeamsPlayType == \"Punt\":\n        kick_plays.at[row.Index,'punterId'] = kick_plays.at[row.Index,'kickerId']\n    elif row.specialTeamsPlayType == \"Field Goal\":\n        kick_plays.at[row.Index,'fg_kickerId'] = kick_plays.at[row.Index,'kickerId']\n        \nkick_plays","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:07.525059Z","iopub.execute_input":"2021-12-04T13:56:07.525301Z","iopub.status.idle":"2021-12-04T13:56:07.984137Z","shell.execute_reply.started":"2021-12-04T13:56:07.525269Z","shell.execute_reply":"2021-12-04T13:56:07.983351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This is a function for adding in the number of each type of play. Note that under this version, it doesn't yet handle the returner column well where laterals are involved.","metadata":{}},{"cell_type":"code","source":"def merge_play_counts(players_df, plays_df, col):\n    \"\"\"A function to add the number of kicks, kick blocks, and returns to a column\n       Note: for now, it just drops the returners (by index) who pose the lateral problem\n       Those players will be manually added back below \"\"\"\n    df = players_df.copy()\n    \n    # handling the returners\n    # for now this drops the problematic ones, to be added back and dealt with\n    if col == 'returnerId':\n        plays_df = plays_df.drop([1753, 2394,5107,6688,11195,12503,16750,16928,16937,19367,19883])\n        plays_df[col] = pd.to_numeric(plays_df[col])\n        \n    # get the number of whatever col I'm looking for into a temp df\n    temp = pd.DataFrame(plays_df[col].value_counts())\n    temp = temp.reset_index().rename(columns={col: f'num_{col[:-4]}s', 'index':'nflId'})\n    \n    # left join the temp df to the main one\n    df = pd.merge(df, temp, how='left', on='nflId')\n    \n    # fill the nan's with 0's\n    df[f'num_{col[:-4]}s'].fillna(value=0, inplace=True)\n    \n    return df\n    ","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:07.985467Z","iopub.execute_input":"2021-12-04T13:56:07.985832Z","iopub.status.idle":"2021-12-04T13:56:07.995031Z","shell.execute_reply.started":"2021-12-04T13:56:07.985799Z","shell.execute_reply":"2021-12-04T13:56:07.994025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"punters\"></a>\n## Part 1: Punters\n\n[Return to top](#top)\n\n","metadata":{}},{"cell_type":"code","source":"punters = players[players[\"Position\"]=='P']\npunters = merge_play_counts(punters, kick_plays, 'punterId')\npunters.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:07.997103Z","iopub.execute_input":"2021-12-04T13:56:07.997507Z","iopub.status.idle":"2021-12-04T13:56:08.041420Z","shell.execute_reply.started":"2021-12-04T13:56:07.997455Z","shell.execute_reply":"2021-12-04T13:56:08.040368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plotting the punters that happen to be in those first 12, completely arbitrary\npunters.head(12).plot.bar(x='displayName', y='num_punts')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.043583Z","iopub.execute_input":"2021-12-04T13:56:08.044163Z","iopub.status.idle":"2021-12-04T13:56:08.453765Z","shell.execute_reply.started":"2021-12-04T13:56:08.044124Z","shell.execute_reply":"2021-12-04T13:56:08.452799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Scouting data\nIn the scouting data, first we need to get the plays for kickoffs and punts.","metadata":{}},{"cell_type":"code","source":"scouting = pd.read_csv('../input/nfl-big-data-bowl-2022/PFFScoutingData.csv')\nscouting.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.455398Z","iopub.execute_input":"2021-12-04T13:56:08.456395Z","iopub.status.idle":"2021-12-04T13:56:08.579655Z","shell.execute_reply.started":"2021-12-04T13:56:08.456343Z","shell.execute_reply":"2021-12-04T13:56:08.578575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"First, I need to get the plays referring to punts. From the [competition page](https://www.kaggle.com/c/nfl-big-data-bowl-2022/data), there are three values in the kickType field that refer to punts: N, normal punts; A, nose-down, Aussie style punts; R, Rugby-style punts.","metadata":{}},{"cell_type":"code","source":"# getting number of each type of kick\nscouting['kickType'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.581164Z","iopub.execute_input":"2021-12-04T13:56:08.581467Z","iopub.status.idle":"2021-12-04T13:56:08.592690Z","shell.execute_reply.started":"2021-12-04T13:56:08.581422Z","shell.execute_reply":"2021-12-04T13:56:08.591621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# dataframe of only the punts\nscouting_punts = scouting[scouting['kickType'].isin(['N','A','R'])]\n\n# dropping some unnecessary fields\nscouting_punts = scouting_punts.drop(['missedTackler','assistTackler','tackler',\n                                      'kickoffReturnFormation','gunners','puntRushers',\n                                      'specialTeamsSafeties','vises','returnDirectionIntended',\n                                      'returnDirectionActual'], axis=1)\n\n# the punt_map df is used to join the plays data (here only kick_plays) with the scouting data\npunt_map = kick_plays[kick_plays['specialTeamsPlayType']==\"Punt\"].drop(['specialTeamsPlayType','kickerId','returnerId','kickBlockerId','ko_kickerId','fg_kickerId'], axis=1)\nscouting_punts = scouting_punts.merge(punt_map, how='left',on=['gameId','playId'])\n\nscouting_punts","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.594096Z","iopub.execute_input":"2021-12-04T13:56:08.594367Z","iopub.status.idle":"2021-12-04T13:56:08.642144Z","shell.execute_reply.started":"2021-12-04T13:56:08.594333Z","shell.execute_reply":"2021-12-04T13:56:08.641243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Adding in some useful fields:","metadata":{}},{"cell_type":"code","source":"# adding a column for punts that went the correct direction\nscouting_punts['kickDirectionCorrect'] = scouting_punts['kickDirectionIntended']==scouting_punts['kickDirectionActual']\n\n# removing the direction columns that are now useless\nscouting_punts = scouting_punts.drop(['kickDirectionIntended','kickDirectionActual'], axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.643734Z","iopub.execute_input":"2021-12-04T13:56:08.643986Z","iopub.status.idle":"2021-12-04T13:56:08.653455Z","shell.execute_reply.started":"2021-12-04T13:56:08.643953Z","shell.execute_reply":"2021-12-04T13:56:08.652525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Check if the number of punts for each punter in the scouting data matches the number from the plays data:","metadata":{}},{"cell_type":"code","source":"# counts records in the scouting data per punter\n# renames the columns for matching\n# merges with punter df \npunt_count_compare = pd.DataFrame(scouting_punts['punterId'].value_counts()).reset_index().rename(columns={'index':'nflId','punterId':'scouting_num_punts'}).merge(punters[['nflId','num_punts']], how='inner')\n\n# adds a column to compare the numbers\npunt_count_compare['difference'] = punt_count_compare['num_punts'] - punt_count_compare['scouting_num_punts']\n\npunt_count_compare.sort_values('difference', ascending=False)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.654831Z","iopub.execute_input":"2021-12-04T13:56:08.655238Z","iopub.status.idle":"2021-12-04T13:56:08.705115Z","shell.execute_reply.started":"2021-12-04T13:56:08.655205Z","shell.execute_reply":"2021-12-04T13:56:08.703676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are slight differences between the two datasets, however they are very small, so I'm going to leave it for the time being. First, I'll add up the categorical columns to get numbers for each punter.\n\nRegarding how the punts were fielded, the following is taken directly from the [data page](#https://www.kaggle.com/c/nfl-big-data-bowl-2022/data):\n\nkickContactType: Detail on how a punt was fielded, or what happened when it wasn't fielded (text).\nPossible values:\n* BB: Bounced Backwards\n* BC: Bobbled Catch from Air\n* BF: Bounced Forwards\n* BOG: Bobbled on Ground\n* CC: Clean Catch from Air\n* CFFG: Clean Field From Ground\n* DEZ: Direct to Endzone\n* ICC: Incidental Coverage Team Contact\n* KTB: Kick Team Knocked Back\n* KTC: Kick Team Catch\n* KTF: Kick Team Knocked Forward\n* MBC: Muffed by Contact with Non-Designated Returner\n* MBDR: Muffed by Designated Returner\n* OOB: Directly Out Of Bounds\n\nI'll seperate those into five: Caught, Ground, Kick Team Touched first, Out of Bounds, Out of Endzone","metadata":{}},{"cell_type":"code","source":"# view the number of each of the categorical punts\npunters_summed_dummy_columns = pd.get_dummies(scouting_punts, columns=['kickType','kickContactType','kickDirectionCorrect']).groupby(['punterId']).sum()\n\n# styles of punting\npunting_styles = punters_summed_dummy_columns[['kickType_A','kickType_N','kickType_R']]\npunting_styles['normalPuntRatio'] = punting_styles['kickType_N']/(punting_styles['kickType_A'] + punting_styles['kickType_N'] + punting_styles['kickType_R'])\npunting_styles = punting_styles.reset_index()\npunting_styles['nflId'] = punting_styles['punterId'] \npunting_styles = punting_styles.drop(['kickType_A','kickType_N','kickType_R','punterId'], axis=1)\n\n\n# punts fielded\npunts_fielded = punters_summed_dummy_columns[['kickContactType_BB','kickContactType_BC','kickContactType_BF',\n                                              'kickContactType_BOG','kickContactType_CC','kickContactType_CFFG',\n                                              'kickContactType_DEZ','kickContactType_ICC','kickContactType_KTB',\n                                              'kickContactType_KTC','kickContactType_KTF','kickContactType_MBC',\n                                              'kickContactType_MBDR','kickContactType_OOB']]\npunts_fielded_sum = punts_fielded['kickContactType_BB'] + punts_fielded['kickContactType_BC'] + punts_fielded['kickContactType_BF'] + punts_fielded['kickContactType_BOG'] + punts_fielded['kickContactType_CC'] + punts_fielded['kickContactType_CFFG'] + punts_fielded['kickContactType_DEZ'] + punts_fielded['kickContactType_ICC'] + punts_fielded['kickContactType_KTB'] + punts_fielded['kickContactType_KTC'] + punts_fielded['kickContactType_KTF'] + punts_fielded['kickContactType_MBC'] + punts_fielded['kickContactType_MBDR'] + punts_fielded['kickContactType_OOB']\npunts_fielded['caughtRatio'] = (punts_fielded['kickContactType_BC'] + punts_fielded['kickContactType_CC'])/punts_fielded_sum\npunts_fielded['groundRatio'] = (punts_fielded['kickContactType_BB'] + punts_fielded['kickContactType_BOG'] + punts_fielded['kickContactType_CFFG'])/punts_fielded_sum\npunts_fielded['kickTeamTouchedFirstRatio'] = (punts_fielded['kickContactType_KTB'] + punts_fielded['kickContactType_KTF'] + punts_fielded['kickContactType_KTC'])/punts_fielded_sum\npunts_fielded['outOfBoundsRatio'] = punts_fielded['kickContactType_OOB']/punts_fielded_sum\npunts_fielded['outOfEZRatio'] = punts_fielded['kickContactType_DEZ']/punts_fielded_sum\npunts_fielded = punts_fielded.reset_index()\npunts_fielded['nflId'] = punts_fielded['punterId']\npunts_fielded = punts_fielded.drop(['kickContactType_BB','kickContactType_BC','kickContactType_BF',\n                                              'kickContactType_BOG','kickContactType_CC','kickContactType_CFFG',\n                                              'kickContactType_DEZ','kickContactType_ICC','kickContactType_KTB',\n                                              'kickContactType_KTC','kickContactType_KTF','kickContactType_MBC',\n                                              'kickContactType_MBDR','kickContactType_OOB','punterId'], axis=1)\n\n\n# kick direction intended\npunts_kick_direction_intended = punters_summed_dummy_columns[['kickDirectionCorrect_True','kickDirectionCorrect_False']]\npunts_kick_direction_intended['intendedDirectionRatio'] = punts_kick_direction_intended['kickDirectionCorrect_True']/(punts_kick_direction_intended['kickDirectionCorrect_True']+punts_kick_direction_intended['kickDirectionCorrect_False'])\npunts_kick_direction_intended = punts_kick_direction_intended.reset_index()\npunts_kick_direction_intended['nflId'] = punts_kick_direction_intended['punterId']\npunts_kick_direction_intended = punts_kick_direction_intended.drop(['punterId','kickDirectionCorrect_True','kickDirectionCorrect_False'], axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.707303Z","iopub.execute_input":"2021-12-04T13:56:08.707666Z","iopub.status.idle":"2021-12-04T13:56:08.762246Z","shell.execute_reply.started":"2021-12-04T13:56:08.707612Z","shell.execute_reply":"2021-12-04T13:56:08.761340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# merge those dataframes to the main punters dataset\npunters = punters.merge(punting_styles, on='nflId')\npunters = punters.merge(punts_fielded, on='nflId')\npunters = punters.merge(punts_kick_direction_intended, on='nflId')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.763922Z","iopub.execute_input":"2021-12-04T13:56:08.764518Z","iopub.status.idle":"2021-12-04T13:56:08.782761Z","shell.execute_reply.started":"2021-12-04T13:56:08.764451Z","shell.execute_reply":"2021-12-04T13:56:08.781958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Next up, I want to get the mean and max hangtimes for each punter (hangtime refers to how long the ball stays in the air).","metadata":{}},{"cell_type":"code","source":"# drop unecessary columns\npunt_hts = scouting_punts.drop(['gameId','playId','snapDetail','snapTime','operationTime','kickType','kickContactType','kickDirectionCorrect'], axis=1)\n\n# calculate mean and max ht by punter\npunt_hts = punt_hts.groupby('punterId').agg(meanHangTime = ('hangTime','mean'),maxHangTime = ('hangTime','max')).reset_index()\npunt_hts = punt_hts.rename(columns={'punterId':'nflId'})\n\n# join it to the main set\npunters = punters.merge(punt_hts, on='nflId')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.784173Z","iopub.execute_input":"2021-12-04T13:56:08.784420Z","iopub.status.idle":"2021-12-04T13:56:08.810886Z","shell.execute_reply.started":"2021-12-04T13:56:08.784388Z","shell.execute_reply":"2021-12-04T13:56:08.809830Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"punters.sort_values('meanHangTime', ascending=False).head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.812646Z","iopub.execute_input":"2021-12-04T13:56:08.813511Z","iopub.status.idle":"2021-12-04T13:56:08.842211Z","shell.execute_reply.started":"2021-12-04T13:56:08.813460Z","shell.execute_reply":"2021-12-04T13:56:08.841148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_top_five(df, column):\n    return df.sort_values(column, ascending=False)[['displayName', 'num_punts',column]].head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.844046Z","iopub.execute_input":"2021-12-04T13:56:08.844567Z","iopub.status.idle":"2021-12-04T13:56:08.850887Z","shell.execute_reply.started":"2021-12-04T13:56:08.844519Z","shell.execute_reply":"2021-12-04T13:56:08.849828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Brett Kern put 15% of his punts out of bounds!","metadata":{}},{"cell_type":"code","source":"get_top_five(punters, 'outOfBoundsRatio')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.855586Z","iopub.execute_input":"2021-12-04T13:56:08.856109Z","iopub.status.idle":"2021-12-04T13:56:08.874854Z","shell.execute_reply.started":"2021-12-04T13:56:08.856072Z","shell.execute_reply":"2021-12-04T13:56:08.873898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Feel free to take this in csv if you'd like:","metadata":{}},{"cell_type":"code","source":"punters.to_csv('punters.csv')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.876305Z","iopub.execute_input":"2021-12-04T13:56:08.876648Z","iopub.status.idle":"2021-12-04T13:56:08.886878Z","shell.execute_reply.started":"2021-12-04T13:56:08.876610Z","shell.execute_reply":"2021-12-04T13:56:08.886000Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='kickers'></a>\n## Part 2: Kickers\n\n[Return to Top](#top)","metadata":{}},{"cell_type":"code","source":"# isolate kickers\nkickers = players[players[\"Position\"]==\"K\"]\n\n# get the proper id's\nkickers = merge_play_counts(kickers, kick_plays, 'ko_kickerId')\nkickers = merge_play_counts(kickers, kick_plays, 'fg_kickerId')\n\nkickers","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.888622Z","iopub.execute_input":"2021-12-04T13:56:08.889791Z","iopub.status.idle":"2021-12-04T13:56:08.942557Z","shell.execute_reply.started":"2021-12-04T13:56:08.889633Z","shell.execute_reply":"2021-12-04T13:56:08.941737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"kickers.head(12).plot.bar(x='displayName', y='num_ko_kicks')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:08.944125Z","iopub.execute_input":"2021-12-04T13:56:08.944904Z","iopub.status.idle":"2021-12-04T13:56:09.353893Z","shell.execute_reply.started":"2021-12-04T13:56:08.944850Z","shell.execute_reply":"2021-12-04T13:56:09.352837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='kickoffs'></a>\n### Part 2a, Kickoffs\nWhat I want to look at:\n* Deep kick average distance\n* Touchback ratio\n* OOB ratio\n* Onside ratio\n* Intended vs Actual Directions","metadata":{}},{"cell_type":"code","source":"# get kickoffs from the plays df\nkickoffs = plays[plays['specialTeamsPlayType'] == 'Kickoff']\n\n# drop unecessary columns\nkickoffs = kickoffs.drop(['playDescription', 'quarter', 'down', 'yardsToGo',\n       'possessionTeam', 'specialTeamsPlayType',\n       'kickBlockerId', 'yardlineSide',\n       'yardlineNumber', 'gameClock', 'penaltyCodes', 'penaltyJerseyNumbers',\n       'penaltyYards', 'preSnapHomeScore', 'preSnapVisitorScore', 'passResult',],axis=1)\n\nkickoffs.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.355517Z","iopub.execute_input":"2021-12-04T13:56:09.356603Z","iopub.status.idle":"2021-12-04T13:56:09.385206Z","shell.execute_reply.started":"2021-12-04T13:56:09.356549Z","shell.execute_reply":"2021-12-04T13:56:09.384341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# getting number of each type of kick\nscouting['kickType'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.386567Z","iopub.execute_input":"2021-12-04T13:56:09.387185Z","iopub.status.idle":"2021-12-04T13:56:09.398505Z","shell.execute_reply.started":"2021-12-04T13:56:09.387148Z","shell.execute_reply":"2021-12-04T13:56:09.397507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In the scouting data, possible values for kickoff plays:\n\n* D: Deep - your normal deep kick with decent hang time\n* F: Flat - different than a Squib in that it will have some hang time and no roll but has a lower trajectory and hang time than a Deep kick off\n* K: Free Kick - Kick after a safety\n* O: Obvious Onside - score and situation dictates the need to regain possession. Also the hands team is on for the returning team\n* P: Pooch kick - high for hangtime but not a lot of distance - usually targeting an upman\n* Q: Squib - low-line drive kick that bounces or rolls considerably, with virtually no hang time\n* S: Surprise Onside - accounting for score and situation an onsides kick that the returning team doesn’t expect. Hands teams probably aren't on the field\n* B: Deep Direct OOB - Kickoff that is aimed deep (regular kickoff) that goes OOB directly (doesn't bounce)\n","metadata":{}},{"cell_type":"code","source":"# dataframe of only the kickoffs\nscouting_kos = scouting[scouting['kickType'].isin(['D','F','K','O','P','Q','S','B'])]\n\nscouting_kos['kickDirectionCorrect'] = scouting_kos['kickDirectionIntended']==scouting_kos['kickDirectionActual']\n\n# drop unecessary columns\nscouting_kos = scouting_kos.drop(['snapDetail','snapTime','operationTime',\n                                  'kickDirectionIntended','kickDirectionActual',\n                                  'missedTackler','assistTackler','tackler',\n                                  'gunners','puntRushers','vises',\n                                  'specialTeamsSafeties','kickContactType',\n                                  'kickoffReturnFormation'], axis=1)\n\n# join with the plays df\nkos = scouting_kos.merge(kickoffs, on=['gameId','playId'])\n\nkos.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.399897Z","iopub.execute_input":"2021-12-04T13:56:09.400715Z","iopub.status.idle":"2021-12-04T13:56:09.446101Z","shell.execute_reply.started":"2021-12-04T13:56:09.400602Z","shell.execute_reply":"2021-12-04T13:56:09.445096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Getting deep kickoff average distance:","metadata":{}},{"cell_type":"code","source":"# calculating the mean and max kickoff distances and hangtimes on deep kicks\ndeep_kos = kos[kos['kickType']=='D']\ndeep_kos = deep_kos.groupby('kickerId').agg(meanKickoffDistance=('kickLength','mean'),\n                                            maxKickoffDistance=('kickLength','max'),\n                                            meanKickoffHangtime=('hangTime','mean'),\n                                            maxKickoffHantime=('hangTime','max')).reset_index().rename(columns={'kickerId':'nflId'})\n# join it to the main set\nkickers = kickers.merge(deep_kos, on='nflId', how='left')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.447377Z","iopub.execute_input":"2021-12-04T13:56:09.447629Z","iopub.status.idle":"2021-12-04T13:56:09.475806Z","shell.execute_reply.started":"2021-12-04T13:56:09.447597Z","shell.execute_reply":"2021-12-04T13:56:09.474475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"kos[kos['kickType']=='D']['specialTeamsResult'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.477769Z","iopub.execute_input":"2021-12-04T13:56:09.478195Z","iopub.status.idle":"2021-12-04T13:56:09.493845Z","shell.execute_reply.started":"2021-12-04T13:56:09.478146Z","shell.execute_reply":"2021-12-04T13:56:09.492631Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# view the number of each of the categorical punts\n# it's going to sum up the gameId's, playId's, hangtimes, etc over each player as well, which is obviously nonsensical, but I'm not using these so it doesn't matter in this context\n# those will get dropped from the df before it is merged with the kickers df\nkickers_summed_dummy_columns = pd.get_dummies(kos, columns=['kickType','specialTeamsResult','kickDirectionCorrect']).groupby(['kickerId']).sum()\n\n# column for the number of kicks\nkickers_summed_dummy_columns['numKickoffs'] = kickers_summed_dummy_columns['kickType_B'] + kickers_summed_dummy_columns['kickType_D'] + kickers_summed_dummy_columns['kickType_F'] + kickers_summed_dummy_columns['kickType_K'] + kickers_summed_dummy_columns['kickType_O'] + kickers_summed_dummy_columns['kickType_P'] + kickers_summed_dummy_columns['kickType_Q'] + kickers_summed_dummy_columns['kickType_S'] \n\n# direction intended\nkickers_summed_dummy_columns['intendedDirectionRatio'] = kickers_summed_dummy_columns['kickDirectionCorrect_True']/(kickers_summed_dummy_columns['kickDirectionCorrect_True']+kickers_summed_dummy_columns['kickDirectionCorrect_False'])\n\n# calculate touchback ratio on deep kicks \nkickers_summed_dummy_columns['touchbackRatio'] = kickers_summed_dummy_columns['specialTeamsResult_Touchback']/kickers_summed_dummy_columns['kickType_D']\n\n# calculate out of bounds ratio\nkickers_summed_dummy_columns['OOBRatio'] = kickers_summed_dummy_columns['kickType_B']/kickers_summed_dummy_columns['numKickoffs']\n\n# calculate onside ratio and recovery rate\nkickers_summed_dummy_columns['onsideRatio'] = kickers_summed_dummy_columns['kickType_O']/kickers_summed_dummy_columns['numKickoffs']\nkickers_summed_dummy_columns['onsideRecoveryRate'] = kickers_summed_dummy_columns['specialTeamsResult_Kickoff Team Recovery']/kickers_summed_dummy_columns['kickType_O']\n\n# fix the df for joining\nkickers_summed_dummy_columns = kickers_summed_dummy_columns.reset_index().rename(columns={'kickerId':'nflId'})\nkickers_summed_dummy_columns = kickers_summed_dummy_columns.drop(kickers_summed_dummy_columns.columns[[x for x in range(1,26)]], axis=1)\n\n# join the new stats columns to the main kickers df\nkickers = kickers.merge(kickers_summed_dummy_columns, on='nflId')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.495828Z","iopub.execute_input":"2021-12-04T13:56:09.497010Z","iopub.status.idle":"2021-12-04T13:56:09.537982Z","shell.execute_reply.started":"2021-12-04T13:56:09.496915Z","shell.execute_reply":"2021-12-04T13:56:09.536829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"kickers.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.539440Z","iopub.execute_input":"2021-12-04T13:56:09.539703Z","iopub.status.idle":"2021-12-04T13:56:09.567981Z","shell.execute_reply.started":"2021-12-04T13:56:09.539670Z","shell.execute_reply":"2021-12-04T13:56:09.567225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='field-goals'></a>\n### Part 2b, Field Goals\n\nFields to add:\n* Accuracy\n* Distance\n* Clutch kicks made (last two minutes of a game to win or tie)","metadata":{}},{"cell_type":"code","source":"games.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.569076Z","iopub.execute_input":"2021-12-04T13:56:09.569515Z","iopub.status.idle":"2021-12-04T13:56:09.584687Z","shell.execute_reply.started":"2021-12-04T13:56:09.569461Z","shell.execute_reply":"2021-12-04T13:56:09.583764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encodeKickingTeamScore(df):\n    if df['possessionTeam'] == df['homeTeamAbbr']:\n        return df['preSnapHomeScore']\n    else:\n        return df['preSnapVisitorScore']\n    \ndef encodeDefendingTeamScore(df):\n    if df['possessionTeam'] == df['visitorTeamAbbr']:\n        return df['preSnapHomeScore']\n    else:\n        return df['preSnapVisitorScore']","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.586534Z","iopub.execute_input":"2021-12-04T13:56:09.587096Z","iopub.status.idle":"2021-12-04T13:56:09.594597Z","shell.execute_reply.started":"2021-12-04T13:56:09.587045Z","shell.execute_reply":"2021-12-04T13:56:09.593637Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def clutchKickIndicator(df):\n    \"\"\"Function to apply to the df to indicate that a given kick was made in the clutch - last three minutes of the game to tie or take the lead\"\"\"\n    if df['clutchKickIndicator']:\n        if 0<= df['defendingTeamScore']-df['kickingTeamScore'] <= 3:\n            if df['specialTeamsResult']=='Kick Attempt Good':\n                return 1\n            elif df['specialTeamsResult']=='Kick Attempt No Good':\n                return 0\n    else:\n        return np.NaN","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.595713Z","iopub.execute_input":"2021-12-04T13:56:09.596444Z","iopub.status.idle":"2021-12-04T13:56:09.618587Z","shell.execute_reply.started":"2021-12-04T13:56:09.596407Z","shell.execute_reply":"2021-12-04T13:56:09.617720Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"field_goals = plays[plays['specialTeamsPlayType'] == 'Field Goal'].drop(['playDescription', \n                                                                         'specialTeamsPlayType', 'yardlineSide','yardlineNumber',\n                                                                         'returnerId', 'kickBlockerId', 'yardsToGo',\n                                                                         'penaltyCodes', 'penaltyJerseyNumbers',\n                                                                         'penaltyYards', 'passResult',\n                                                                         'kickReturnYardage', 'playResult',\n                                                                         ], axis=1)\n\n# bring in the home and away columns from the games dataset \nfield_goals = field_goals.merge(games[['gameId','homeTeamAbbr','visitorTeamAbbr']], on='gameId')\n\n# add the clutch kick indicator\nfield_goals['clutchKickIndicator'] = (field_goals['gameClock'].str.slice(start=0, stop=2).isin(['02','01','00'])) & (field_goals['quarter'] == 4)\n\n# add the more useful score columns\nfield_goals['kickingTeamScore'] = field_goals.apply(encodeKickingTeamScore, axis=1).astype('int64')\nfield_goals['defendingTeamScore'] = field_goals.apply(encodeDefendingTeamScore, axis=1).astype('int64')\n\n# add the clutch kick made and missed for stats\nfield_goals['clutchKickMade'] = field_goals.apply(clutchKickIndicator, axis=1)\nfield_goals['clutchKickMissed'] = field_goals['clutchKickMade'] == 0\n\n# get rid of a couple columns now made redundant\nfield_goals = field_goals.drop(['preSnapHomeScore','preSnapVisitorScore',], axis=1)\n\n# mean and max kicks made\nkicks_made_stats = field_goals[field_goals['specialTeamsResult'] == 'Kick Attempt Good'].groupby('kickerId').agg(meanKickLength_hit=('kickLength','mean'),\n                                                                                                                 maxKickLength_hit=('kickLength','max'),\n                                                                                                                 clutchKicksMade=('clutchKickMade','sum')).reset_index().rename(columns={'kickerId':'nflId'})\n\n# mean, min and max kicks missed\nkicks_missed_stats = field_goals[field_goals['specialTeamsResult'] == 'Kick Attempt No Good'].groupby('kickerId').agg(meanKickLength_missed=('kickLength','mean'),\n                                                                                                                 maxKickLength_missed=('kickLength','max'),\n                                                                                                                 shortestKickLength_missed=('kickLength','min'),\n                                                                                                                 clutchKicksMissed=('clutchKickMissed','sum')).reset_index().rename(columns={'kickerId':'nflId'})\n\n# finally, add these to the kickers df\nkickers = kickers.merge(kicks_made_stats, on='nflId')\nkickers = kickers.merge(kicks_missed_stats, on='nflId')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.620130Z","iopub.execute_input":"2021-12-04T13:56:09.620780Z","iopub.status.idle":"2021-12-04T13:56:09.879069Z","shell.execute_reply.started":"2021-12-04T13:56:09.620727Z","shell.execute_reply":"2021-12-04T13:56:09.878272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# longest kicks?\nkickers.sort_values('maxKickLength_hit', ascending=False).head(12)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.880335Z","iopub.execute_input":"2021-12-04T13:56:09.880696Z","iopub.status.idle":"2021-12-04T13:56:09.924492Z","shell.execute_reply.started":"2021-12-04T13:56:09.880665Z","shell.execute_reply":"2021-12-04T13:56:09.923718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Feel free to take this in csv if you'd like:","metadata":{}},{"cell_type":"code","source":"kickers.to_csv('kickers.csv')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.925740Z","iopub.execute_input":"2021-12-04T13:56:09.926106Z","iopub.status.idle":"2021-12-04T13:56:09.934815Z","shell.execute_reply.started":"2021-12-04T13:56:09.926069Z","shell.execute_reply":"2021-12-04T13:56:09.934094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='returners'></a>\n## Part 3: Returners\n\n[Return to Top](#top)","metadata":{}},{"cell_type":"code","source":"returners = merge_play_counts(players, kick_plays, 'returnerId')\nreturners = returners[returners['num_returns'] > 0]\nreturners","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.936649Z","iopub.execute_input":"2021-12-04T13:56:09.936961Z","iopub.status.idle":"2021-12-04T13:56:09.983904Z","shell.execute_reply.started":"2021-12-04T13:56:09.936905Z","shell.execute_reply":"2021-12-04T13:56:09.982859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"11 kicks and punts involved laterals where multiple players could be considered a returner. ","metadata":{}},{"cell_type":"code","source":"returns_with_laterals = plays[plays['returnerId'].str.contains(';', na=False)][['playDescription','returnerId']]\nreturns_with_laterals","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:09.985417Z","iopub.execute_input":"2021-12-04T13:56:09.985741Z","iopub.status.idle":"2021-12-04T13:56:10.009914Z","shell.execute_reply.started":"2021-12-04T13:56:09.985705Z","shell.execute_reply":"2021-12-04T13:56:10.009138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Return to Top](#top)\n","metadata":{}},{"cell_type":"code","source":"returners.sort_values(by='num_returns', ascending=False)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:10.011306Z","iopub.execute_input":"2021-12-04T13:56:10.011873Z","iopub.status.idle":"2021-12-04T13:56:10.036795Z","shell.execute_reply.started":"2021-12-04T13:56:10.011833Z","shell.execute_reply":"2021-12-04T13:56:10.035883Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now I'm going to add in an extra return for every player who touched the ball in a return involving a lateral. There were also two players (Terry Godwin, Chris Claybrooks) who were on two kickoffs involving laterals, so they'll get two extra.\n\n","metadata":{}},{"cell_type":"code","source":"returns_with_laterals","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:10.038613Z","iopub.execute_input":"2021-12-04T13:56:10.039152Z","iopub.status.idle":"2021-12-04T13:56:10.056454Z","shell.execute_reply.started":"2021-12-04T13:56:10.039114Z","shell.execute_reply":"2021-12-04T13:56:10.055287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# nflId's of the players involved with the above lateral plays\nids = [41238,43880,43329,44029,46130,36473,46221,44923,45555,46309,42718,46277,42094,52631,48020,52737,45719,46506,46669]\n\n# for the two guys with multiple such plays\nother_ids = [52631, 48020]","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:10.058179Z","iopub.execute_input":"2021-12-04T13:56:10.058702Z","iopub.status.idle":"2021-12-04T13:56:10.068137Z","shell.execute_reply.started":"2021-12-04T13:56:10.058657Z","shell.execute_reply":"2021-12-04T13:56:10.066974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"returners.loc[returners['nflId'].isin(ids), 'num_returns'] += 1\nreturners.loc[returners['nflId'].isin(other_ids), 'num_returns'] += 1","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:10.069743Z","iopub.execute_input":"2021-12-04T13:56:10.070032Z","iopub.status.idle":"2021-12-04T13:56:10.086341Z","shell.execute_reply.started":"2021-12-04T13:56:10.069995Z","shell.execute_reply":"2021-12-04T13:56:10.085216Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"returners.sort_values(by=['num_returns'], ascending=False)","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:10.087838Z","iopub.execute_input":"2021-12-04T13:56:10.088851Z","iopub.status.idle":"2021-12-04T13:56:10.112764Z","shell.execute_reply.started":"2021-12-04T13:56:10.088812Z","shell.execute_reply":"2021-12-04T13:56:10.111772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Return to Top](#top)","metadata":{}},{"cell_type":"code","source":"returners.head(12).plot.bar(x='displayName', y='num_returns')","metadata":{"execution":{"iopub.status.busy":"2021-12-04T13:56:10.114070Z","iopub.execute_input":"2021-12-04T13:56:10.114319Z","iopub.status.idle":"2021-12-04T13:56:10.521228Z","shell.execute_reply.started":"2021-12-04T13:56:10.114286Z","shell.execute_reply":"2021-12-04T13:56:10.520205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## *TO BE CONTINUED....*","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}