{"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-10-15T18:25:06.666572Z","iopub.execute_input":"2021-10-15T18:25:06.667537Z","iopub.status.idle":"2021-10-15T18:25:06.682481Z","shell.execute_reply.started":"2021-10-15T18:25:06.667488Z","shell.execute_reply":"2021-10-15T18:25:06.681605Z"},"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-10-15T18:25:06.684168Z","iopub.execute_input":"2021-10-15T18:25:06.684849Z","iopub.status.idle":"2021-10-15T18:25:06.859965Z","shell.execute_reply.started":"2021-10-15T18:25:06.684806Z","shell.execute_reply":"2021-10-15T18:25:06.859061Z"},"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-10-15T18:25:06.861429Z","iopub.execute_input":"2021-10-15T18:25:06.862276Z","iopub.status.idle":"2021-10-15T18:25:07.104775Z","shell.execute_reply.started":"2021-10-15T18:25:06.862226Z","shell.execute_reply":"2021-10-15T18:25:07.103919Z"},"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-10-15T18:25:07.107717Z","iopub.execute_input":"2021-10-15T18:25:07.108105Z","iopub.status.idle":"2021-10-15T18:25:07.146842Z","shell.execute_reply.started":"2021-10-15T18:25:07.108060Z","shell.execute_reply":"2021-10-15T18:25:07.145933Z"},"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-10-15T18:25:07.149853Z","iopub.execute_input":"2021-10-15T18:25:07.150135Z","iopub.status.idle":"2021-10-15T18:25:07.388349Z","shell.execute_reply.started":"2021-10-15T18:25:07.150101Z","shell.execute_reply":"2021-10-15T18:25:07.387514Z"},"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-10-15T18:25:07.389625Z","iopub.execute_input":"2021-10-15T18:25:07.389879Z","iopub.status.idle":"2021-10-15T18:25:07.425568Z","shell.execute_reply.started":"2021-10-15T18:25:07.389832Z","shell.execute_reply":"2021-10-15T18:25:07.424764Z"},"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-10-15T18:25:07.426693Z","iopub.execute_input":"2021-10-15T18:25:07.426958Z","iopub.status.idle":"2021-10-15T18:25:07.723014Z","shell.execute_reply.started":"2021-10-15T18:25:07.426929Z","shell.execute_reply":"2021-10-15T18:25:07.722124Z"},"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-10-15T18:25:07.724202Z","iopub.execute_input":"2021-10-15T18:25:07.724499Z","iopub.status.idle":"2021-10-15T18:25:08.523173Z","shell.execute_reply.started":"2021-10-15T18:25:07.724461Z","shell.execute_reply":"2021-10-15T18:25:08.522132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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'] >= 100.0]\nlong_returns","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:25:08.524643Z","iopub.execute_input":"2021-10-15T18:25:08.524998Z","iopub.status.idle":"2021-10-15T18:25:08.559354Z","shell.execute_reply.started":"2021-10-15T18:25:08.524953Z","shell.execute_reply":"2021-10-15T18:25:08.558464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"So, only 9 kickoffs in the dataset were returned for more 100 yards. If we look at the `playDescription` field we can see that the play result of `TOUCHDOWN` is recorded here. We can use this to find all kickoffs that were returned for a touchdown, regardless of return length.","metadata":{}},{"cell_type":"code","source":"td_returns = kickoff_returns_df.loc[kickoff_returns_df['playDescription'].str.contains('TOUCHDOWN')]\ntd_returns.head()","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:25:08.563645Z","iopub.execute_input":"2021-10-15T18:25:08.563957Z","iopub.status.idle":"2021-10-15T18:25:08.598125Z","shell.execute_reply.started":"2021-10-15T18:25:08.563923Z","shell.execute_reply":"2021-10-15T18:25:08.597215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"So we can see that only 21 out of 2,921 kickoff returns resulted in a touchdown. That's only about 0.7%.","metadata":{}},{"cell_type":"markdown","source":"### Which teams gave up the most kickoff returns for a touchdown?","metadata":{}},{"cell_type":"code","source":"ax = td_returns.groupby('possessionTeam').size().plot.barh(figsize=(14,6), title=\"Kickoff returns for a TD by kicking team\")\nax.set_ylabel('Kicking Team')","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:25:08.600129Z","iopub.execute_input":"2021-10-15T18:25:08.600479Z","iopub.status.idle":"2021-10-15T18:25:08.904670Z","shell.execute_reply.started":"2021-10-15T18:25:08.600438Z","shell.execute_reply":"2021-10-15T18:25:08.903645Z"},"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-10-15T18:25:08.906493Z","iopub.execute_input":"2021-10-15T18:25:08.906823Z","iopub.status.idle":"2021-10-15T18:25:46.991774Z","shell.execute_reply.started":"2021-10-15T18:25:08.906779Z","shell.execute_reply":"2021-10-15T18:25:46.991075Z"},"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-10-15T18:25:46.992796Z","iopub.execute_input":"2021-10-15T18:25:46.993579Z","iopub.status.idle":"2021-10-15T18:25:47.006759Z","shell.execute_reply.started":"2021-10-15T18:25:46.993544Z","shell.execute_reply":"2021-10-15T18:25:47.006108Z"},"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 = td_returns.loc[134]['playDescription']\nplay_desc","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:25:47.007666Z","iopub.execute_input":"2021-10-15T18:25:47.008293Z","iopub.status.idle":"2021-10-15T18:25:47.028076Z","shell.execute_reply.started":"2021-10-15T18:25:47.008258Z","shell.execute_reply":"2021-10-15T18:25:47.027433Z"},"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=2956, gameId=2018090903, color_dict=team_colors)","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:25:47.028961Z","iopub.execute_input":"2021-10-15T18:25:47.029685Z","iopub.status.idle":"2021-10-15T18:26:08.840460Z","shell.execute_reply.started":"2021-10-15T18:25:47.029650Z","shell.execute_reply":"2021-10-15T18:26:08.839531Z"},"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-10-15T18:26:08.841802Z","iopub.execute_input":"2021-10-15T18:26:08.842077Z","iopub.status.idle":"2021-10-15T18:26:08.923613Z","shell.execute_reply.started":"2021-10-15T18:26:08.842045Z","shell.execute_reply":"2021-10-15T18:26:08.923047Z"},"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-10-15T18:26:08.924563Z","iopub.execute_input":"2021-10-15T18:26:08.925224Z","iopub.status.idle":"2021-10-15T18:26:08.944427Z","shell.execute_reply.started":"2021-10-15T18:26:08.925182Z","shell.execute_reply":"2021-10-15T18:26:08.943201Z"},"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-10-15T18:26:08.945878Z","iopub.execute_input":"2021-10-15T18:26:08.946717Z","iopub.status.idle":"2021-10-15T18:26:08.988345Z","shell.execute_reply.started":"2021-10-15T18:26:08.946684Z","shell.execute_reply":"2021-10-15T18:26:08.987472Z"},"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-10-15T18:26:08.989967Z","iopub.execute_input":"2021-10-15T18:26:08.990833Z","iopub.status.idle":"2021-10-15T18:26:08.999655Z","shell.execute_reply.started":"2021-10-15T18:26:08.990786Z","shell.execute_reply":"2021-10-15T18:26:08.998765Z"},"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-10-15T18:26:09.001320Z","iopub.execute_input":"2021-10-15T18:26:09.001952Z","iopub.status.idle":"2021-10-15T18:26:09.334346Z","shell.execute_reply.started":"2021-10-15T18:26:09.001907Z","shell.execute_reply":"2021-10-15T18:26:09.333430Z"},"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-10-15T18:26:09.335984Z","iopub.execute_input":"2021-10-15T18:26:09.336669Z","iopub.status.idle":"2021-10-15T18:26:09.345158Z","shell.execute_reply.started":"2021-10-15T18:26:09.336625Z","shell.execute_reply":"2021-10-15T18:26:09.344223Z"},"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-10-15T18:26:09.346719Z","iopub.execute_input":"2021-10-15T18:26:09.347071Z","iopub.status.idle":"2021-10-15T18:26:09.834108Z","shell.execute_reply.started":"2021-10-15T18:26:09.347019Z","shell.execute_reply":"2021-10-15T18:26:09.833050Z"},"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-10-15T18:26:09.835662Z","iopub.execute_input":"2021-10-15T18:26:09.836111Z","iopub.status.idle":"2021-10-15T18:26:10.119032Z","shell.execute_reply.started":"2021-10-15T18:26:09.836066Z","shell.execute_reply":"2021-10-15T18:26:10.118143Z"},"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-10-15T18:26:10.120460Z","iopub.execute_input":"2021-10-15T18:26:10.120767Z","iopub.status.idle":"2021-10-15T18:26:10.404305Z","shell.execute_reply.started":"2021-10-15T18:26:10.120727Z","shell.execute_reply":"2021-10-15T18:26:10.403708Z"},"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-10-15T18:26:10.405215Z","iopub.execute_input":"2021-10-15T18:26:10.405752Z","iopub.status.idle":"2021-10-15T18:26:10.617827Z","shell.execute_reply.started":"2021-10-15T18:26:10.405719Z","shell.execute_reply":"2021-10-15T18:26:10.616922Z"},"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-10-15T18:26:10.619054Z","iopub.execute_input":"2021-10-15T18:26:10.619453Z","iopub.status.idle":"2021-10-15T18:26:10.847978Z","shell.execute_reply.started":"2021-10-15T18:26:10.619419Z","shell.execute_reply":"2021-10-15T18:26:10.846194Z"},"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-10-15T18:26:10.849237Z","iopub.execute_input":"2021-10-15T18:26:10.849453Z","iopub.status.idle":"2021-10-15T18:26:10.857241Z","shell.execute_reply.started":"2021-10-15T18:26:10.849427Z","shell.execute_reply":"2021-10-15T18:26:10.856351Z"},"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-10-15T18:26:10.862510Z","iopub.execute_input":"2021-10-15T18:26:10.862755Z","iopub.status.idle":"2021-10-15T18:26:11.101728Z","shell.execute_reply.started":"2021-10-15T18:26:10.862720Z","shell.execute_reply":"2021-10-15T18:26:11.100888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"That looks like the distribution for most of the other types of kicks. It looks like these small mistakes in kick direction aren't that costly in terms of return yards.\n\n### How do missed tackles impact returns?\n\nThe last thing I want to look at is plays where there are missed tackles. This should correlate to longer returns more than any other feature of this data set.","metadata":{}},{"cell_type":"code","source":"missed_tackles_df = kickoff_returns_df[kickoff_returns_df['missedTackler'].notnull()]\nmissed_tackles_df['kickReturnYardage'].plot.kde(figsize=(14,3), title=\"Distribution of Return Yards on Missed Tackles\")","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:26:11.103140Z","iopub.execute_input":"2021-10-15T18:26:11.103440Z","iopub.status.idle":"2021-10-15T18:26:11.367299Z","shell.execute_reply.started":"2021-10-15T18:26:11.103400Z","shell.execute_reply":"2021-10-15T18:26:11.366489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It looks like the average return is longer (25 yards) when tackles are missed, plus there are small bumps in the distribution at 50 and 100 yards. This is as expected. It looks like most of the really long returns we saw earlier are in this subset.","metadata":{}},{"cell_type":"code","source":"missed_tackles_df['missedTackles'] = missed_tackles_df['missedTackler'].str.split(';').str.len()\nmissed_tackles_df['missedTackles'].value_counts().plot.barh(figsize=(9,4), title=\"Returns with Missed Tackles\")","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:30:21.640238Z","iopub.execute_input":"2021-10-15T18:30:21.640935Z","iopub.status.idle":"2021-10-15T18:30:21.857727Z","shell.execute_reply.started":"2021-10-15T18:30:21.640895Z","shell.execute_reply":"2021-10-15T18:30:21.856680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = missed_tackles_df[['missedTackles', 'kickReturnYardage']].boxplot(by='missedTackles', figsize=(14,8), vert=False)\nax.set_xlabel(None)\nax.set_title(None)","metadata":{"execution":{"iopub.status.busy":"2021-10-15T18:28:35.922366Z","iopub.execute_input":"2021-10-15T18:28:35.922683Z","iopub.status.idle":"2021-10-15T18:28:36.195471Z","shell.execute_reply.started":"2021-10-15T18:28:35.922653Z","shell.execute_reply":"2021-10-15T18:28:36.194640Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Summary\n\nMost kickoffs are basically the same. Teams try to kick the ball out of the back of the endzone to avoid a return. When they fail to do this, the majority of returns are around 20 yards. Onside kicks and returns for touchdowns are extremely rare. The best things kicking teams can do to avoid long returns are:\n\n1. Kick the ball through the end zone\n2. Don't miss tackles on returns","metadata":{}}]}