{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport ipywidgets as wg\nfrom IPython.core.display import HTML\nimport matplotlib.animation as anim\nimport matplotlib.pyplot as plt\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-11-16T00:49:53.052456Z","iopub.execute_input":"2021-11-16T00:49:53.052803Z","iopub.status.idle":"2021-11-16T00:49:53.16267Z","shell.execute_reply.started":"2021-11-16T00:49:53.052716Z","shell.execute_reply":"2021-11-16T00:49:53.161734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Load plays data and see how many plays were kickoffs","metadata":{}},{"cell_type":"code","source":"plays_df = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/plays.csv')\nprint(plays_df.shape)\nplays_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:50:05.582262Z","iopub.execute_input":"2021-11-16T00:50:05.583148Z","iopub.status.idle":"2021-11-16T00:50:05.709597Z","shell.execute_reply.started":"2021-11-16T00:50:05.5831Z","shell.execute_reply":"2021-11-16T00:50:05.708774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plays_df['specialTeamsPlayType'].value_counts().plot.barh(figsize=(8,4), title=\"Special teams plays by type\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:50:13.086282Z","iopub.execute_input":"2021-11-16T00:50:13.086622Z","iopub.status.idle":"2021-11-16T00:50:13.38418Z","shell.execute_reply.started":"2021-11-16T00:50:13.086588Z","shell.execute_reply":"2021-11-16T00:50:13.383294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Out of 19,979 total special teams plays in the dataset, nearly 8,000 were kickoffs, the most frequent type of special teams play.","metadata":{}},{"cell_type":"code","source":"kickoffs_df = plays_df.loc[plays_df['specialTeamsPlayType'] == 'Kickoff']\nkickoffs_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:50:21.016259Z","iopub.execute_input":"2021-11-16T00:50:21.017325Z","iopub.status.idle":"2021-11-16T00:50:21.052047Z","shell.execute_reply.started":"2021-11-16T00:50:21.017281Z","shell.execute_reply":"2021-11-16T00:50:21.051119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### How many kickoffs were returned?","metadata":{}},{"cell_type":"code","source":"kickoffs_df['specialTeamsResult'].value_counts().plot.barh(figsize=(9,4), title=\"Kickoffs by result\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:50:31.693447Z","iopub.execute_input":"2021-11-16T00:50:31.693773Z","iopub.status.idle":"2021-11-16T00:50:31.947467Z","shell.execute_reply.started":"2021-11-16T00:50:31.693737Z","shell.execute_reply":"2021-11-16T00:50:31.946512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Well over half (4,773) of all kickoffs (7,843) went for a touchback. Only 2,921, or 37% were returned.","metadata":{}},{"cell_type":"code","source":"kickoff_returns_df = kickoffs_df.loc[kickoffs_df['specialTeamsResult'] == 'Return']\nkickoff_returns_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:50:40.215904Z","iopub.execute_input":"2021-11-16T00:50:40.218336Z","iopub.status.idle":"2021-11-16T00:50:40.254334Z","shell.execute_reply.started":"2021-11-16T00:50:40.218276Z","shell.execute_reply":"2021-11-16T00:50:40.253463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### What's the average and maximum return yardage given up by each team?\n\nLet's start by looking at the distribution of return yards overall, then look at a boxplot for each team.","metadata":{}},{"cell_type":"code","source":"kickoff_returns_df[['kickReturnYardage']].plot.hist(figsize=(14,6), title=\"Kickoff Return Yards Frequency\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:51:14.913841Z","iopub.execute_input":"2021-11-16T00:51:14.914606Z","iopub.status.idle":"2021-11-16T00:51:15.216308Z","shell.execute_reply.started":"2021-11-16T00:51:14.914561Z","shell.execute_reply":"2021-11-16T00:51:15.215311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = kickoff_returns_df[['possessionTeam', 'kickReturnYardage']].boxplot(by='possessionTeam', figsize=(14,10), vert=False)\nax.set_xlabel(None)\nax.set_title(None)","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:51:51.241087Z","iopub.execute_input":"2021-11-16T00:51:51.241391Z","iopub.status.idle":"2021-11-16T00:51:52.048978Z","shell.execute_reply.started":"2021-11-16T00:51:51.241359Z","shell.execute_reply":"2021-11-16T00:51:52.047924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"From both the histogram and the boxplot, we can see that most kickoff returns were concentrated around 20 yards, but there were several kickoffs that were returned for more than 100 yards. Those must have been for touchdowns, so let's look at that subset to see if there's anything in the description that indicates a TD. We can use that to get all kickoffs that were returned for a touchdown.","metadata":{}},{"cell_type":"code","source":"long_returns = kickoff_returns_df.loc[kickoff_returns_df['kickReturnYardage'] >= 50.0]\nlong_returns","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:53:33.801875Z","iopub.execute_input":"2021-11-16T00:53:33.802188Z","iopub.status.idle":"2021-11-16T00:53:33.840056Z","shell.execute_reply.started":"2021-11-16T00:53:33.802155Z","shell.execute_reply":"2021-11-16T00:53:33.839199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"So we can see that only 62 out of 2,921 kickoff returns resulted in a gains > 50 yds. About 2%. ","metadata":{}},{"cell_type":"markdown","source":"### Which teams gave up the most kickoff returns for a touchdown?","metadata":{}},{"cell_type":"code","source":"ax = long_returns.groupby('possessionTeam').size().plot.barh(figsize=(14,6), title=\"Kickoff returns Greater than 50 yds by kicking team\")\nax.set_ylabel('Kicking Team')","metadata":{"execution":{"iopub.status.busy":"2021-11-16T00:53:49.969543Z","iopub.execute_input":"2021-11-16T00:53:49.969843Z","iopub.status.idle":"2021-11-16T00:53:50.397046Z","shell.execute_reply.started":"2021-11-16T00:53:49.969801Z","shell.execute_reply":"2021-11-16T00:53:50.396159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualize a Kickoff Return\n\nCredit to [Joseph Mohr](https://www.kaggle.com/josephvm) for the following animation. I took the `getPlayAnimation` from his [NFL BDB 2022 - Play Animation & Tracking EDA](https://www.kaggle.com/josephvm/nfl-bdb-2022-play-animation-tracking-eda) notebook and modified it to look slightly more like a football field.","metadata":{}},{"cell_type":"code","source":"# Load one of the tracking data files so we have the details for the animation\ntracking_df = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/tracking2018.csv')","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:01:39.880775Z","iopub.execute_input":"2021-11-16T01:01:39.881141Z","iopub.status.idle":"2021-11-16T01:02:11.242564Z","shell.execute_reply.started":"2021-11-16T01:01:39.881106Z","shell.execute_reply":"2021-11-16T01:02:11.241682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def getPlayAnimation(df, playId=2956, gameId=2018090903, color_dict={'home': 'red', 'away': 'blue', 'football': 'brown'}):\n    # function to draw one frame\n    def plotFrame(i):\n        one_frame = one_play[ one_play['frameId'] == i+1 ]\n        ax.cla()\n\n        plt.xticks(range(0, 121, 10), fontsize=15)\n        ax.set_xticklabels([None, 'G', '10', '20', '30', '40', '50', '40', '30', '20', '10', 'G', None])\n        ax.tick_params(axis='x', colors='white')\n        \n        # Constants from frame to frame\n        ax.set_xlim([0, 120])\n        ax.set_ylim([0, 53.3])\n        for yardline in range(10, 111, 10):\n            ax.plot([yardline, yardline], [0, 53.3], c='white')\n        \n        # What changes\n        ax.scatter(one_frame['x'], one_frame['y'], c=one_frame['team'].transform(lambda x: color_dict[x]), s=64)\n        ax.set_title('Frame: {}'.format(i+1), fontsize=15, c='white')\n    \n    # Get df of tracking data for one play\n    one_play = df[(df['playId'] == playId) & (df['gameId'] == gameId)]\n    \n    fig, ax = plt.subplots(figsize=(12,6))\n    \n    # Don't show y-axis ticks or tick labels\n    ax.axes.get_yaxis().set_visible(False)\n    \n    # Set background colors\n    fig.patch.set_facecolor('xkcd:leaf green')\n    ax.set_facecolor('xkcd:leaf green')\n    \n    # Set the field border color and line width\n    for spine in ax.spines.values():\n        spine.set_edgecolor('white')\n        spine.set_linewidth(2.5)\n    \n    play_anim = anim.FuncAnimation(fig, plotFrame, frames=one_play['frameId'].max()-1, interval=100)\n    html = play_anim.to_html5_video()\n    plt.close(fig)\n    return HTML(html)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-11-16T01:02:14.297432Z","iopub.execute_input":"2021-11-16T01:02:14.29799Z","iopub.status.idle":"2021-11-16T01:02:14.311306Z","shell.execute_reply.started":"2021-11-16T01:02:14.297958Z","shell.execute_reply":"2021-11-16T01:02:14.310685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's look at the first kickoff return for a touchdown in our data set, which has TEN kicking to MIA.","metadata":{}},{"cell_type":"code","source":"play_desc = long_returns.loc[139]['playDescription']\nplay_desc","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:06:40.29693Z","iopub.execute_input":"2021-11-16T01:06:40.297258Z","iopub.status.idle":"2021-11-16T01:06:40.304537Z","shell.execute_reply.started":"2021-11-16T01:06:40.29722Z","shell.execute_reply":"2021-11-16T01:06:40.303622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"team_colors = {'home': 'xkcd:light turquoise',\n               'away': 'xkcd:cobalt',\n               'football': 'xkcd:mud'}\ngetPlayAnimation(tracking_df, playId=3300, gameId=2018090903, color_dict=team_colors)","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:05:26.05641Z","iopub.execute_input":"2021-11-16T01:05:26.057276Z","iopub.status.idle":"2021-11-16T01:05:45.874901Z","shell.execute_reply.started":"2021-11-16T01:05:26.057219Z","shell.execute_reply":"2021-11-16T01:05:45.874155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Kick type, direction, hang-time, and return formation\n\nLet's look at more attributes of the play by merging in the scouting data with the data on kickoffs that were returned.","metadata":{}},{"cell_type":"code","source":"scouting_df = pd.read_csv('/kaggle/input/nfl-big-data-bowl-2022/PFFScoutingData.csv')\nscouting_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:07:18.925419Z","iopub.execute_input":"2021-11-16T01:07:18.925718Z","iopub.status.idle":"2021-11-16T01:07:19.036643Z","shell.execute_reply.started":"2021-11-16T01:07:18.925686Z","shell.execute_reply":"2021-11-16T01:07:19.035845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Keep the columns that are related to kickoffs\nkickoff_cols = ['gameId', 'playId', 'hangTime', 'kickType', 'kickDirectionIntended', 'kickDirectionActual', 'missedTackler',\n                'returnDirectionIntended', 'returnDirectionActual', 'kickoffReturnFormation', 'specialTeamsSafeties']\nkickoff_scouting_df = scouting_df[kickoff_cols]\nkickoff_scouting_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:11:01.412583Z","iopub.execute_input":"2021-11-16T01:11:01.412922Z","iopub.status.idle":"2021-11-16T01:11:01.433326Z","shell.execute_reply.started":"2021-11-16T01:11:01.412889Z","shell.execute_reply":"2021-11-16T01:11:01.432477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Merge the scouting data with the kickoffs that were returned.\nkickoff_returns_df = kickoff_returns_df.merge(kickoff_scouting_df, how='left', on=['gameId', 'playId'])\nkickoff_returns_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:11:31.440291Z","iopub.execute_input":"2021-11-16T01:11:31.440556Z","iopub.status.idle":"2021-11-16T01:11:31.496259Z","shell.execute_reply.started":"2021-11-16T01:11:31.44053Z","shell.execute_reply":"2021-11-16T01:11:31.495281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### What are the most common kick types and kickoff return formations?","metadata":{}},{"cell_type":"code","source":"kickoff_returns_df['kickType'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:12:40.5244Z","iopub.execute_input":"2021-11-16T01:12:40.524998Z","iopub.status.idle":"2021-11-16T01:12:40.534126Z","shell.execute_reply.started":"2021-11-16T01:12:40.524956Z","shell.execute_reply":"2021-11-16T01:12:40.533287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = kickoff_returns_df[['kickType', 'kickReturnYardage']].boxplot(by='kickType', figsize=(14,6), vert=False)\nax.set_xlabel(None)\nax.set_title(None)","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:13:18.094449Z","iopub.execute_input":"2021-11-16T01:13:18.094743Z","iopub.status.idle":"2021-11-16T01:13:18.421917Z","shell.execute_reply.started":"2021-11-16T01:13:18.094712Z","shell.execute_reply":"2021-11-16T01:13:18.42132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since the deep kick is the most common, it's also the kick type with the most returns for long yardage.\n\nThe kickoff formation is a 3-digit code indicating the number of players in the Front Wall, Mid Wall, and Back Wall during the kick. Let's look at which formations are most popular, then at the distribution of return yards for each formation.","metadata":{}},{"cell_type":"code","source":"kickoff_returns_df['kickoffReturnFormation'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:14:17.512248Z","iopub.execute_input":"2021-11-16T01:14:17.512589Z","iopub.status.idle":"2021-11-16T01:14:17.522069Z","shell.execute_reply.started":"2021-11-16T01:14:17.512554Z","shell.execute_reply":"2021-11-16T01:14:17.521215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = kickoff_returns_df[['kickoffReturnFormation', 'kickReturnYardage']].boxplot(by='kickoffReturnFormation', figsize=(14,8), vert=False)\nax.set_xlabel(None)\nax.set_title(None)","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:30:54.484999Z","iopub.execute_input":"2021-11-16T01:30:54.487203Z","iopub.status.idle":"2021-11-16T01:30:55.239361Z","shell.execute_reply.started":"2021-11-16T01:30:54.487144Z","shell.execute_reply":"2021-11-16T01:30:55.238421Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Not surprisingly, most of the long returns were when the return team was in the most popular formation.\n\n### Is hang time related to return yardage?\n\nLet's look at the distribution of hang times of kicks and how it relates to return yards.","metadata":{}},{"cell_type":"code","source":"kickoff_returns_df['hangTime'].plot.kde(figsize=(14, 3), title=\"Distribution of Kickoff Hang Times (s)\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:31:02.206738Z","iopub.execute_input":"2021-11-16T01:31:02.207848Z","iopub.status.idle":"2021-11-16T01:31:03.536497Z","shell.execute_reply.started":"2021-11-16T01:31:02.207775Z","shell.execute_reply":"2021-11-16T01:31:03.535868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"kickoff_returns_df.plot.scatter(x='hangTime', y='kickReturnYardage', figsize=(14,6), title=\"Kickoff Return Yards vs. Kick Hang Time (s)\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:31:25.353127Z","iopub.execute_input":"2021-11-16T01:31:25.353484Z","iopub.status.idle":"2021-11-16T01:31:25.653927Z","shell.execute_reply.started":"2021-11-16T01:31:25.353444Z","shell.execute_reply":"2021-11-16T01:31:25.653064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Again, there doesn't appear to be much relationship here. Since the vast majority of kickoffs have a hang time between 3.5 and 4.5 seconds, it makes sense that all of long returns would be on this type of kick.","metadata":{}},{"cell_type":"markdown","source":"### Is kick direction related to return yards?","metadata":{}},{"cell_type":"code","source":"kickoff_returns_df['kickDirectionIntended'].value_counts().plot.barh(figsize=(9,3), title=\"Intended Kick Direction\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:32:17.080481Z","iopub.execute_input":"2021-11-16T01:32:17.081569Z","iopub.status.idle":"2021-11-16T01:32:17.334467Z","shell.execute_reply.started":"2021-11-16T01:32:17.081516Z","shell.execute_reply":"2021-11-16T01:32:17.333436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"kickoff_returns_df['kickDirectionActual'].value_counts().plot.barh(figsize=(9,3), title=\"Actual Kick Direction\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:32:32.59098Z","iopub.execute_input":"2021-11-16T01:32:32.592123Z","iopub.status.idle":"2021-11-16T01:32:32.814178Z","shell.execute_reply.started":"2021-11-16T01:32:32.592058Z","shell.execute_reply":"2021-11-16T01:32:32.813104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It makes sense that most kicks would be straight up the middle, since it's harder to kick the ball out of bounds that way, and easier to kick it through the end zone, which is what most teams are trying to do most of the time. Let's look at how often the intended kick direction doesn't match the actual direction.","metadata":{}},{"cell_type":"code","source":"(kickoff_returns_df['kickDirectionIntended'] == kickoff_returns_df['kickDirectionActual']).sum() / len(kickoff_returns_df)","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:33:07.851364Z","iopub.execute_input":"2021-11-16T01:33:07.852427Z","iopub.status.idle":"2021-11-16T01:33:07.864329Z","shell.execute_reply.started":"2021-11-16T01:33:07.852375Z","shell.execute_reply":"2021-11-16T01:33:07.863244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"98.9% accuracy at anything is pretty impressive, but let's take a closer look at just those plays where the kick direction doesn't match the intended direction.","metadata":{}},{"cell_type":"code","source":"missed_direction = kickoff_returns_df[kickoff_returns_df['kickDirectionIntended'] != kickoff_returns_df['kickDirectionActual']]\nmissed_direction['kickReturnYardage'].plot.kde(figsize=(14,3), title=\"Distribution of Return Yards on Missed Directional Kicks\")","metadata":{"execution":{"iopub.status.busy":"2021-11-16T01:34:00.486232Z","iopub.execute_input":"2021-11-16T01:34:00.486605Z","iopub.status.idle":"2021-11-16T01:34:00.733211Z","shell.execute_reply.started":"2021-11-16T01:34:00.486572Z","shell.execute_reply":"2021-11-16T01:34:00.732305Z"},"trusted":true},"execution_count":null,"outputs":[]}]}