{"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":"# Markdown\nfrom IPython.core.display import display, HTML, Javascript\nimport IPython.display\n\n# Data reading, Preprocessing and analysis\nimport numpy as np\nimport pandas as pd\n\n# Data Visualization\nimport plotly.express as px\nimport plotly.graph_objects as go\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Warnings\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Data\ngame_data = pd.read_csv('../input/nfl-big-data-bowl-2022/games.csv')\nplays_data = pd.read_csv('../input/nfl-big-data-bowl-2022/plays.csv')\ntracking = []\nfor n in range(2018, 2020+1):\n    tracking.append(pd.read_csv('../input/nfl-big-data-bowl-2022/tracking'+str(n)+'.csv'))\n\n# Updating Data\ngame_data = game_data[['gameId', 'season', 'homeTeamAbbr', 'visitorTeamAbbr']]\nplays_data = plays_data[['gameId', 'playId', 'possessionTeam', 'specialTeamsPlayType', 'specialTeamsResult', 'kickLength', 'absoluteYardlineNumber', 'down']]\nfor n in range(3):\n    tracking[n] = tracking[n][['gameId', 'playId', 'time', 'team', 'x', 'y', 'displayName', 'playDirection']]\n\n    \n# Merging Data\nstamp = pd.merge(game_data, plays_data, on=['gameId'])\n\nfull2020 = pd.merge(stamp, tracking[2], on=['gameId', 'playId'])\nfull2019 = pd.merge(stamp, tracking[1], on=['gameId', 'playId'])\nfull2018 = pd.merge(stamp, tracking[0], on=['gameId', 'playId'])\n\n# For punt returns plays only\nfull2020 = full2020[(full2020['specialTeamsPlayType'] == 'Punt') & (full2020['specialTeamsResult'] == 'Return')]\nfull2019 = full2019[(full2019['specialTeamsPlayType'] == 'Punt') & (full2019['specialTeamsResult'] == 'Return')]\nfull2018 = full2018[(full2018['specialTeamsPlayType'] == 'Punt') & (full2018['specialTeamsResult'] == 'Return')]\n\n\n\n# CSS from Schubert's notebook\n# CSS styling for markdown\nstyling = \"\"\"\n    <style>\n        .main-heading{\n            background-color: #bd1e21;\n            color: white !important;\n            font-family: Helvetica;\n            font-size: 32px !important;\n            padding: 12px 12px;\n            margin-bottom: 5px;\n            border-radius: 4px;\n            box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px;\n        }\n\n        .sub-heading{\n            width: auto !important;\n            background-color: #ad2e30;\n            color: white !important;\n            font-family: Helvetica;\n            font-size: 24px !important;\n            padding: 10px 12px;\n            margin-bottom: 3px;\n            box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;\n        }\n    </style>\n\"\"\"\nHTML(styling)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1>Punt Return, Blocking Scores</h1>\n<h2 class=\"main-heading\">Introduction</h2>\n\n&nbsp;&nbsp;&nbsp;The normal stats about Punt Return teams show only the simple stats which is not telling the truth and what happened behind the scenes like returns or average returns and so on. What about the Block of players who prevent the punt returner from the opponent team? This notebook gives you new insights about calculating a new metric which isn't simple but will help you to know which is the team having the best Punt Return team in terms of preventing the punt returner from being tackled by the opponent's team players. If there is any objection about the sensitive parameters' values used in this notebook don't worry. All that in the accounts and the code will give you the ability to change each parameter you need and explains what it does specifically.","metadata":{}},{"cell_type":"code","source":"# To display an image uploaded on Kaggle\nfrom IPython.display import Image\nImage(\"../input/photos/Why-removebg-preview.png\")","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;&nbsp;&nbsp;The Reason is the most likely play to do in the 4th down and the punt result also is the most likely result to happen. Another reason is that having gained yards doesn't tell how skilled your whole punt return team is?","metadata":{}},{"cell_type":"code","source":"def pie_chart(data, col, title, center_word, explode=None, colors=['lightgray', 'lightseagreen', 'lightblue', 'skyblue']):\n        '''\n        Plotting your categorical variable with Pie chart having the variable name in it's center and with your specific colors\n        title: The title of the graph\n        colors: List of colors to each value of variable's values\n        '''\n        \n        fig = go.Figure()\n        num_types = len(data[col].unique())\n        if not explode:\n            explode = [0]*num_types\n            \n        fig.add_trace(\n            go.Pie(\n                labels=data[col],\n                values=None,\n                hole=.4,\n                pull=explode,\n                title=center_word,\n                titlefont={'color':None, 'size':22},\n                )\n            )\n        fig.update_traces(\n            hoverinfo='label+value',\n            textinfo='label+percent',\n            textfont_size=14,\n            marker=dict(\n                colors=colors[:num_types],\n                line=dict(color='#000000',\n                width=2)\n                )\n            )\n        \n        # Updating the layout\n        fig.update_layout(title=title, \n                          font_family=\"San Serif\",\n                          bargap=0.2,\n                          titlefont={'size': 24},\n                          legend=dict(\n                          orientation=\"v\", y=1, yanchor=\"top\", x=1.25, xanchor=\"right\")                 \n                          )\n        fig.show()\n    \nfourth_down_plays = plays_data.query('down == 4')\npie_chart(fourth_down_plays, 'specialTeamsPlayType', 'The Play Types in the fourth down', 'PlayType')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"punt_plays = plays_data.query('down == 4 and specialTeamsPlayType == \"Punt\"')\npie_chart(fourth_down_plays, 'specialTeamsResult', 'The Play Results in Punts', 'PlayResult', [0.1]+[0]*4)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# To display an image uploaded on Kaggle\nfrom IPython.display import Image\nImage(\"../input/photos/How-removebg-preview (1).png\")","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"&nbsp;&nbsp;&nbsp;First, the focus will be only on the moment the player receives the ball from the opposing team and then runs until the ball is cut from him. The metric will then start working so that every time **the distance between any player on the opposing team and the punt returner is about three yards** or less(you can change this distance, this is from the changeable parameters) from either side (think of this as a circle and we'll call it the **circle of danger**), this distance will be added to a variable in our equation That is, a block score. For accuracy, a value of three will be added minus this value, since the smaller it is, the worse it is. after we get the block score and the returns gains, then make the **metric equals (block score / returns gains)** putting in accounts the differences in returns gains, then we can improve it further by make the **metric equals (1/itself)** this will make the higher it is, the better it is.\n\n&nbsp;&nbsp;&nbsp;**Distance Calculation For each Play**, it will be calculated by taking the distance between each player in the opposing team and Punt returner at each part of each second, then taking the average distance in each second (summation of the distance in each part of the second / number of distances), if this average distance is higher than **3 yards** it will be ignored (not added to the block score) else **3 - this average distance** will be added to the block score. After adding all these values during one play and then dividing the result by the yards gained and then flipping the fraction (or keeping it the same) this will be calculated for all the punts played by this team and taking the average from all of them we will get our metric for this team in any desired season.","metadata":{}},{"cell_type":"markdown","source":"## Explanation Video for the metric\n\nhttps://youtu.be/LTz8Yy-5ME0","metadata":{}},{"cell_type":"code","source":"from base64 import b64encode\n\ndef play(filename):\n    html = ''\n    video = open(filename,'rb').read()\n    src = 'data:video/mp4;base64,' + b64encode(video).decode()\n    html += '<video width=1000 controls autoplay loop><source src=\"%s\" type=\"video/mp4\"></video>' % src \n    return HTML(html)\n\nplay('../input/videonflmet/1_6.mp4')","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h2 class=\"sub-heading\">Used Data</h2>","metadata":{}},{"cell_type":"markdown","source":"&nbsp;&nbsp;&nbsp;At this notebook, we've choose some columns from the datasets and left others to focus deeply just on our metric. Of course Tracking Data will be used along with Plays Data as they are the most important datasets in our analysis, but there will be another used dataset such as Game Data. So in the following few lines there will be a discussion about which columns will be used from each one and why some datasets have been left such as Players Data and PFF Scouting Data. So first, let's start with **<mark>Game Data</mark>**. In the analysis, each season and each game specifically will matter as there are some plays share their playId, but in different games, so it is a must not a choice to loop on each game then loop on each play with in it. homeTeamAbbr and visitorTeamAbbr will help to know who will be in the situation of punting and who will be in the situation of returning. From **<mark>Plays Data</mark>** gameId and playId will be used for merging the datasets. specialTeamsPlayType will be used to determine only punting plays, kickLength will help to know where is the location of the Punt Returner when catching the ball, specialTeamsResult will be used to determine only the punts where return is the reaction of the opposing team, absoluteYardlineNumber helps understand where the ball is as in the exploratory notebook, assuring from our results was important. **<mark>Tracking Data</mark>**, gameId and playId are used for merging the dataset with last ones, x and y are from the most important columns have been used as they will help to calculate the distance in each part of a second and completing the rest of the calculation process, displayName will help us to know from where this player is he from home or away team or he can be the ball itself, and playDirection will help to know where was the Punt Player when catching the ball as the calculation of his position will differ depending on left or right. ","metadata":{}},{"cell_type":"markdown","source":"<h2 class=\"sub-heading\">Hyper Parameters</h2>","metadata":{}},{"cell_type":"markdown","source":"&nbsp;&nbsp;&nbsp;In the metric calculation process, there are some parameters that can be changed for coming reasons such as **`punt_return_initial_position_error`** which will differ for plays some of them have 0.1 error, some have 0.5 and believe it or not some have more than 2.4!! So this parameter must be set to a value so this value will be higher than the maximum error for all the plays. There are some advantages and disadvantages about each hyper parameter. In the next few lines, there will be a brief definition of each hyper parameter and discussion about its effects such as what will happen if we increase it or decrease it? How will this hyper parameter help us in the metric calculation process and so on. Before this there will be a quick definitions about the parameters or variables have been made to speak about hyperparameters professionaly.\n\n## Variables/Parameters and Concepts\n\n**`Expected_Ball_Position`**: Ball position can be expected by the ball initial position when being snapped (The start of whole play) and the Kick Length. (Adding or Subtracting them will differ according to the play direction).\n\n**`opponent_player_distance`**: This is the distance for a player in the opposing team to the Punt Returner. \n\n**`avg_distance_per_second`**: This is the average of all **\"opponent_player_distance\"** for a player in a second.\n\n**`Risky Distance`**: This is the distance limit for **\"avg_distance_per_second\"** which will make it be considered in the metric (This is bad for the Punt Returner team) as a risk try to tackle the Punt Returner. (This is a hyper parameter)\n\n**`Risk Circle`**: This circle as shown in the video is a circle its radius is the risky distance (this is a hyper parameter which will be discussed next) from any player in the opposing team to Punt Returner (the distance will be used is **\"avg_distance_per_second\"**).\n\n**`added value`**: It's actually happen if the \"avg_distance_per_second\" equals or less than the **\"Risky Distance\"** and it equals --> 'Risky Distance' -  **\"avg_distance_per_second\"**.   ('**Risky Distance** -' here to make the more closer the more worse, think of it)\n\n**`Blocking Score`**: The summation of all **added values**.\n\n**`Returner Score`**: It is the yards gain by the Punt Return Team. (end position of the ball - initial position of the ball, These positions starts when the punt returner catchs the ball)\n\n**`Metric Score`**: It is our topic :-), it equals **\"Blocking Score\"** / **\"Returner Score\"** if you want to make it the higher it is, the worse it is else flip the fraction to be **\"Returner Score\"** / **\"Blocking Score\"**.\n\n\n## Hyper Parameters\n\n**`punt_return_initial_position_error`**: This hyper parameter will allow the errors less than it, errors here are the absolute value of ball real position when being catched - \"Expected_Ball_Position\". Of course making it higher will permit many plays to be calculated without errors, but also will make problems!! How is this? This because if it is set to very high value it may consider the ball when it is on the air (Because of the punt) start calculating all the process of metric calculation as the \"opponent_player_distance\" is actually from the ball and the players of the opposing team and as the z-axis is not considered, the ball may start adding values to the \"**Blocking Score**\" as the avg_distance_per_second will be very small. (**Default value for season 2020 will be about 2.5**)\n\n**`Risky Distance`**: It's definition is above, gapping it or widing it will affect the block score, but \"Typical NFL players are approximately 2 yards tall. Typical NFL player arm length is approximately 1 yard. Thus, considering the extreme example of a player who is diving to make a tackle, 2-3 yards would be a reasonable value for tackle range\". This words written by DS. Thompson Bliss thanks to him for his helpful comments. **The default value will be set to 3 yards** which is changeable for the above reason. Making it less than 3 will decrease the blocking score as it will not take players in 3 yards distance in consideration which is bad as they are very risky.\n\n**`Used_Function`**: This is a statistcal way of looking it the data, but you can instead of taking all the above parameters and calculate their averages you can take the median for example. **Default is \"Mean\"**","metadata":{}},{"cell_type":"markdown","source":"In the next cell there will be a function, you can use it to see the plan view of the game. Determine only gameId and playId","metadata":{}},{"cell_type":"code","source":"def calc_dist(x1, y1, x2, y2):\n    '''\n    Calculates the distance between two points\n    '''\n    return ( (x1-x2)**2 + (y1-y2)**2 )**0.5\n\ndef plan_view(data, gameId, playId):\n    '''\n    Plot the plan view of the \n    '''\n    \n    df = data\n    df = df[(df['gameId'] == gameId) & (df['playId'] == playId)] # Select the specific game and play\n    \n    # Plotting the scatter plot (As a video)\n    fig = px.scatter(df, x=\"x\", y=\"y\", animation_frame=\"time\", color=\"team\", hover_name='displayName', template='plotly_dark',\n                    range_x=[0, 120], range_y=[0, 53.3])\n\n    \n    \n    # The coming three for loops for putting lines to seem like a football stadium\n    for i in range(10, 50+10, 10):\n\n        fig.add_vline(x=i+10, line_dash='solid', annotation_text=str(i), annotation_position=\"top right\", line_color='white', \n                      annotation=dict(font_size=30, font_family=\"Times New Roman\", font_color='white'),\n                      fillcolor=\"white\", line_width=2)\n\n    for i in range(40, 10-10, -10):\n\n        fig.add_vline(x=60+(50-i), line_dash='solid', annotation_text=str(i), annotation_position=\"top right\", line_color='white', \n                      annotation=dict(font_size=30, font_family=\"Times New Roman\", font_color='white'),\n                      fillcolor=\"white\", line_width=2)\n\n    for i in [10, 110]:\n\n        fig.add_vline(x=i, line_dash='dash', annotation_text='End Zone', annotation_position=\"bottom right\", line_color='white', \n                      annotation=dict(font_size=15, font_family=\"Times New Roman\", font_color='white'),\n                      fillcolor=\"white\", line_width=2)\n        \n\n    # To hide tick labels and the axis itself\n    fig.update_yaxes(showticklabels=False, visible=False)\n    fig.update_xaxes(showticklabels=False, visible=False)\n    \n    # Color bg to green\n    fig.update_layout(plot_bgcolor='green')\n    \n    # Update duration\n    fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 30\n    fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 5\n    fig.show()\n    \n\n    \n\n# Testing Part\nplan_view(full2020, 2020110500, 3674)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 class=\"main-heading\">Metric Implementation</h1>","metadata":{}},{"cell_type":"markdown","source":"&nbsp;&nbsp;&nbsp;After the brief overview of each side of the problem and understanding its idea, viewing the video and trying the function for making movie from scatter plot frames should Expand your perceptions and gets you ready for the implementation. Before going throw it don't forget that this notebook was an example of how you NFL can use this metric, but not for punt return only it can be done with kickoff return too, but as NFL stats site separate kick off return and punt return stats we did it in a similar manner, but don't worry the differences will not be that big as it will be  very easy to make it for kickoff return only or for both of them. \n\n## `Metric Formula Used =  Returner_score / Block_score`\n## `punt_return_initial_position_error = 2.5`\n## `Risk Distance = 3`","metadata":{}},{"cell_type":"code","source":"def metric_stats(dataframe, season, punt_return_initial_position_error= 2.5, risk_distance= 3):\n    \n    teams_scores = []\n    teams = []\n    return_scores = []\n    block_scores = []\n    return_fin_scores = []\n    block_fin_scores = []\n\n    teams_names = list(dataframe['visitorTeamAbbr'].unique()) # use in full dataframe\n    df = dataframe.copy()\n    \n    for team in teams_names:\n\n\n        game_data_per_team = df[(df['season'] == season) & ((df['visitorTeamAbbr'] == team) | (df['homeTeamAbbr'] == team))]\n        games_per_team = game_data_per_team['gameId'].unique()\n        \n        # Setting them for all teams\n        scores = []\n        block_scores = []\n        return_scores = []\n        for game in games_per_team:\n\n            plays_data_per_game_per_team = game_data_per_team.query(f'gameId == {game}')\n            plays_per_game_per_team = plays_data_per_game_per_team['playId'].unique()\n            for play in plays_per_game_per_team:\n\n                plays_data_per_play_per_game_per_team = plays_data_per_game_per_team[(plays_data_per_game_per_team['playId'] == play) & (plays_data_per_game_per_team['possessionTeam'] != team)]\n                if plays_data_per_play_per_game_per_team.shape[0] == 0:\n                    continue\n\n                # Group them all to color them in different colors\n                home = plays_data_per_play_per_game_per_team.query(\"team == 'home'\")\n                away = plays_data_per_play_per_game_per_team.query(\"team == 'away'\")\n                football = plays_data_per_play_per_game_per_team.query('team == \"football\"')\n\n                # Merge them again; this was done to have x and y for each of them\n                test = pd.merge(home, away, on=['gameId', 'playId', 'time'], suffixes=['_home', '_away'])\n                test = pd.merge(test, football, on=['gameId', 'playId', 'time'])\n                test[['x_football', 'y_football']] = test[['x', 'y']]\n\n                # Distance between any player of them opposing team and the ball\n                test['distance_metric'] = calc_dist(test['x_home'], test['y_home'], test['x_football'], test['y_football'])\n\n                # Initial position of the ball (on x-axis only)\n                start_kick_x = test.loc[0, 'x_football']\n\n                # The length of the kick, be aware that any value in this series will be the same you can pick any value not just value in the 0 index \n                kick_length = df[(df['gameId'] == game) & (df['playId'] == play)]['kickLength'].values[0]\n\n                # Left direction will be separated from right direction as one of them will be by adding start_kick_x and kick_length and the other one is by subtracting\n                if test['playDirection'].unique()[0] == 'left':\n\n                    start_time = (test[abs(test['x_football'] - (start_kick_x - kick_length)) <= punt_return_initial_position_error]['time']).values[0]\n                else:\n                    start_time = (test[abs(test['x_football'] - (start_kick_x + kick_length)) <= punt_return_initial_position_error]['time']).values[0]\n\n\n\n                # Updating time data type\n                plays_data_per_play_per_game_per_team['time_update'] = pd.to_datetime(plays_data_per_play_per_game_per_team['time'])\n                plays_data_per_play_per_game_per_team = plays_data_per_play_per_game_per_team[plays_data_per_play_per_game_per_team['time_update'] >= start_time]\n\n\n\n                # Final thing in the metric calculation\n\n                # Prepare test dataframe\n                test['time_update'] = pd.to_datetime(test['time'])\n                test = test[test['time_update'] >= start_time]\n                test['second'] = test['time_update'].dt.second\n\n                # Calc averages per player in each second\n                avg_per_player_for_each_sec = test.groupby(['playId', 'displayName_home', 'second']).agg({'distance_metric':'mean'}).reset_index()\n                avgs_filtered = avg_per_player_for_each_sec.query(f'distance_metric <= {risk_distance}')\n                sums = 3 - avgs_filtered['distance_metric']\n                block_score = sum(sums.values)\n\n                # Calculating the number of yards gained by the punt return team \n                start_point = test['x_football'].values[0]\n                end_point = test['x_football'].values[-1]\n                returner_score = end_point - start_point if test['playDirection'].unique()[0] == 'left' else start_point - end_point\n                if returner_score < 0:\n                    returner_score = 0\n\n                # Final score for a play\n                final_score_per_play = returner_score / block_score if block_score != 0 else returner_score / 0.1\n                scores.append(final_score_per_play)\n                return_scores.append(returner_score)\n                block_scores.append(block_score)\n\n\n        metric_score_per_team = round( sum(scores) / len(scores), 2 )\n        block_score_per_team = round( sum(block_scores) / len(block_scores), 2 )\n        return_score_per_team = round( sum(return_scores) / len(return_scores), 2 )\n        block_fin_scores.append(block_score_per_team)\n        return_fin_scores.append(return_score_per_team)\n        teams_scores.append(metric_score_per_team)\n        teams.append(team)\n        \n    return teams, teams_scores, block_fin_scores, return_fin_scores","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # Distribution of the metric for season 2020 as an example","metadata":{}},{"cell_type":"code","source":"full_stats_2020 = metric_stats(full2020, 2020)\nteams, teams_scores = full_stats_2020[:2]\nsns.kdeplot(teams_scores)\nplt.xlabel('Metric Score')\nplt.title('Distribution of the metric in season 2020')\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It seems to be normally distributed, so the metric doesn't have typos :-), another interesting thing is that most teams has 0.75 to 2 as their score.","metadata":{}},{"cell_type":"markdown","source":"## Highest Scores in season 2020","metadata":{}},{"cell_type":"code","source":"def plot_highest(teams, teams_scores, season, n=10):\n    reorder = sorted([(team, score) for team, score in zip(teams, teams_scores)], key=lambda x : x[1])\n    reorder = reorder[::-1] # reverse it\n    highest_teams = [reorder[i][0] for i in range(n)]\n    highest_scores = [reorder[i][1] for i in range(n)]\n    plt.bar(highest_teams, highest_scores)\n    plt.title(f'Highest {n} teams in season {season}')\n    plt.ylabel('Metric Score')\n    plt.xlabel('Team')\n    plt.show()\n    \nplot_highest(teams, teams_scores, 2020)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Highest Scores in season 2019","metadata":{}},{"cell_type":"code","source":"full_stats_2019 = metric_stats(full2019, 2019)\nteams, teams_scores = full_stats_2019[:2]\nplot_highest(teams, teams_scores, 2019)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Highest Scores in season 2018","metadata":{}},{"cell_type":"code","source":"full_stats_2018 = metric_stats(full2018, 2018)\nteams, teams_scores = full_stats_2018[:2]\nplot_highest(teams, teams_scores, 2018)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 class=\"main-heading\">Conclusion & Recommendations</h1>","metadata":{}},{"cell_type":"markdown","source":"&nbsp;&nbsp;&nbsp;As explained above there are lots of hyper parameters and parameters for this metric which are changeable, the metric show new way of looking at your data not just full score or gained yardage but the stringness of the players in the punt return team. Ohe of the most interesting fact about this metric is the flexability, it can be used in any return play such as Kickoff returns not just Punt returns. Also here there will be some additional recommendations to be used with this metric. Score can be calculated by several ways as explained above, choosing <mark>blocking score / return score</mark> was because our main goal was blocking score, but as we wish to do it in more accurate way, the metric must deal with different scenarios such as different gained yards. As if the punt return team won many yardages, this should increase the number of opposing team players tackles or attacking him which will cause increasing blocking score and to manage this we add the second term which is return score and the metric also deals with minus gained yards. The second way of scoring is <mark>return score / blocking score</mark> it has been made to make the metric the higher it is, the better it is, that's it :-)","metadata":{}},{"cell_type":"markdown","source":"## References:\n- <a href=\"https://www.nfl.com/stats/team-stats/special-teams/punt-returns/2021/reg/all\">NFL Stats</a>\n\n- <a href=\"https://www.kaggle.com/c/nfl-big-data-bowl-2022/discussion/2979530\">Thread for asking about the risky distance</a>","metadata":{}}]}