Learn how to use Python to generate advanced WR stats.
If you have any questions about the code here, feel free to reach out to me on Twitter or on Reddit.
For this notebook, let's put together a table that gives us some key fantasy football stats for WRs. Our table is going to include fantasy points per game, average targets, air yards, average target share in games played, average air yards in games played, weighted opportunity rating, and redzone looks. This is the data that I believe has the most fantasy football applicability. Everything else is probably secondary.
To top it off, we're also going to be including player headshots and team logos and add some dynamic highlighting to our DataFrame, similar to something you'd do in Excel.
Our data source is going to be nflfastR which contains NFL play by play data updated daily, to which I've set a Python package for easy loading in pandas. The cell below will install the external package in your notebook runtime.
The %%capture magic command here just supresses the output for our cell.
And as always, let's import some libraries we'll be needing for this project.
Loading NFL play by play data with the nflfastpy Python package is as easy as the one-liner below. The positional argument here is the season.
We can see we have 24,214 plays to work with at the time I'm writing this. If you're running this code in a week other than week 10 of the current NFL season, your results for the following data will vary.
What we want to do now is run a groupby and find each receivers yards gained, receiving touchdowns, receptions, air yards, and also their fantasy points scored. We can quickly add a column to our Dataframe using the assign method. Here, we're establishing a column of raw_rec_fpts. Raw receiving fantasy points is a player's points scored only because of receiving, which for receivers is going to be the bulk of their production. We don't account for fumbles, WR end arounds, WR trick passing plays, etc so the results may differ from your league formats fantasy points scored per game.
receiver_player_id | posteam | game_id | pass_attempt | yards_gained | air_yards | complete_pass | pass_touchdown | raw_rec_fpts | |
---|---|---|---|---|---|---|---|---|---|
2168 | 32013030-2d30-3033-3633-373065ee5506 | LAC | 2020_08_LAC_DEN | 1.0 | -7.0 | -5.0 | 1.0 | 0.0 | 0.3 |
1713 | 32013030-2d30-3033-3532-3433c2333695 | PHI | 2020_06_BAL_PHI | 2.0 | -6.0 | 17.0 | 1.0 | 0.0 | 0.4 |
690 | 32013030-2d30-3033-3233-393431c33be1 | DEN | 2020_01_TEN_DEN | 2.0 | -6.0 | -5.0 | 1.0 | 0.0 | 0.4 |
564 | 32013030-2d30-3033-3138-30361fd87e06 | LA | 2020_05_LA_WAS | 2.0 | -6.0 | -2.0 | 1.0 | 0.0 | 0.4 |
15 | 32013030-2d30-3032-3334-35395dc60da5 | GB | 2020_02_DET_GB | 1.0 | -6.0 | -4.0 | 1.0 | 0.0 | 0.4 |
We want to now find each teams air yards thrown and targets thrown for each individual game, and then merge that data with the table above. We are then going to calculate an average target share and average air yards share for each receiver.
game_id | posteam | air_yards | pass_attempt | |
---|---|---|---|---|
0 | 2020_01_ARI_SF | ARI | 192.0 | 37.0 |
1 | 2020_01_ARI_SF | SF | 225.0 | 32.0 |
2 | 2020_01_CHI_DET | CHI | 353.0 | 36.0 |
3 | 2020_01_CHI_DET | DET | 372.0 | 41.0 |
4 | 2020_01_CLE_BAL | BAL | 255.0 | 25.0 |
And now wemerge the data on both the game_id and posteam column (posteam means team in possession of the football).
receiver_player_id | posteam | game_id | pass_attempt_player | yards_gained | air_yards_player | complete_pass | pass_touchdown | raw_rec_fpts | air_yards_team | pass_attempt_team | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 32013030-2d30-3032-3231-32373ce51f62 | LV | 2020_01_LV_CAR | 1.0 | 2.0 | 2.0 | 1.0 | 0.0 | 1.2 | 161.0 | 28.0 |
1 | 32013030-2d30-3033-3135-3439d46a53e9 | LV | 2020_01_LV_CAR | 1.0 | 23.0 | 23.0 | 1.0 | 1.0 | 9.3 | 161.0 | 28.0 |
2 | 32013030-2d30-3033-3136-3130db0aa3c4 | LV | 2020_01_LV_CAR | 8.0 | 45.0 | 30.0 | 6.0 | 0.0 | 10.5 | 161.0 | 28.0 |
3 | 32013030-2d30-3033-3239-3732ec926fb5 | LV | 2020_01_LV_CAR | 3.0 | 23.0 | 1.0 | 3.0 | 0.0 | 5.3 | 161.0 | 28.0 |
4 | 32013030-2d30-3033-3330-3235189aefb0 | LV | 2020_01_LV_CAR | 1.0 | 15.0 | 6.0 | 1.0 | 0.0 | 2.5 | 161.0 | 28.0 |
Now that we have the data merged, we can calculate target share and air yards share by creating two new columns in our rec_df DataFrame.
receiver_player_id | posteam | game_id | pass_attempt_player | yards_gained | air_yards_player | complete_pass | pass_touchdown | raw_rec_fpts | air_yards_team | pass_attempt_team | target_share | air_yards_share | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 32013030-2d30-3032-3231-32373ce51f62 | LV | 2020_01_LV_CAR | 1.0 | 2.0 | 2.0 | 1.0 | 0.0 | 1.2 | 161.0 | 28.0 | 0.035714 | 0.012422 |
1 | 32013030-2d30-3033-3135-3439d46a53e9 | LV | 2020_01_LV_CAR | 1.0 | 23.0 | 23.0 | 1.0 | 1.0 | 9.3 | 161.0 | 28.0 | 0.035714 | 0.142857 |
2 | 32013030-2d30-3033-3136-3130db0aa3c4 | LV | 2020_01_LV_CAR | 8.0 | 45.0 | 30.0 | 6.0 | 0.0 | 10.5 | 161.0 | 28.0 | 0.285714 | 0.186335 |
3 | 32013030-2d30-3033-3239-3732ec926fb5 | LV | 2020_01_LV_CAR | 3.0 | 23.0 | 1.0 | 3.0 | 0.0 | 5.3 | 161.0 | 28.0 | 0.107143 | 0.006211 |
4 | 32013030-2d30-3033-3330-3235189aefb0 | LV | 2020_01_LV_CAR | 1.0 | 15.0 | 6.0 | 1.0 | 0.0 | 2.5 | 161.0 | 28.0 | 0.035714 | 0.037267 |
Now we just want to grab the average results, which will give us back average raw receiving fantasy points scored, average target share, etc. etc.
receiver_player_id | pass_attempt_player | yards_gained | air_yards_player | complete_pass | pass_touchdown | raw_rec_fpts | air_yards_team | pass_attempt_team | target_share | air_yards_share | |
---|---|---|---|---|---|---|---|---|---|---|---|
257 | 32013030-2d30-3033-3432-3836149d738d | 13.00 | 184.000 | 120.000000 | 9.000000 | 1.000000 | 33.400000 | 224.000000 | 34.000 | 0.382353 | 0.535714 |
86 | 32013030-2d30-3033-3133-383188f79eec | 11.50 | 112.500 | 111.166667 | 8.833333 | 1.333333 | 28.083333 | 287.666667 | 34.000 | 0.332879 | 0.400927 |
371 | 32013030-2d30-3033-3536-343097915ff1 | 8.50 | 98.500 | 123.625000 | 5.375000 | 1.000000 | 21.225000 | 313.875000 | 35.875 | 0.244524 | 0.414175 |
122 | 32013030-2d30-3033-3232-31312f766863 | 8.75 | 76.875 | 92.000000 | 6.625000 | 0.875000 | 19.562500 | 313.875000 | 35.875 | 0.236870 | 0.287703 |
365 | 32013030-2d30-3033-3535-3932f90568c6 | 8.80 | 87.000 | 99.000000 | 5.800000 | 0.800000 | 19.300000 | 330.400000 | 34.800 | 0.245506 | 0.302467 |
Let's quickly filter and rename some columns to clean up our data before proceeding to the next step.
receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | |
---|---|---|---|---|---|---|
257 | 32013030-2d30-3033-3432-3836149d738d | 33.400000 | 13.00 | 120.000000 | 0.382353 | 0.535714 |
86 | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.50 | 111.166667 | 0.332879 | 0.400927 |
371 | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.50 | 123.625000 | 0.244524 | 0.414175 |
122 | 32013030-2d30-3033-3232-31312f766863 | 19.562500 | 8.75 | 92.000000 | 0.236870 | 0.287703 |
365 | 32013030-2d30-3033-3535-3932f90568c6 | 19.300000 | 8.80 | 99.000000 | 0.245506 | 0.302467 |
Below, we are going to grab redzone looks. A target is a redzone look if the difference between air yards and yardline_100 is 0. yardline_100 goes from 99 to 1, where 1 represents the goal line. The difference between air yards and this yard line column won't fall below 0, even if the ball is thrown, for example, in the back of the endzone (which would add 10 more yards in terms of air yards from the goal line). That was initial assumption, to which we'd use <= 0, but this is not the case. So here, we check if the difference is 0, and then sum the results.
receiver_player_id | Redzone Looks | |
---|---|---|
371 | 32013030-2d30-3033-3536-343097915ff1 | 10 |
315 | 32013030-2d30-3033-3438-333761eb5105 | 10 |
46 | 32013030-2d30-3033-3030-3335960ad201 | 10 |
122 | 32013030-2d30-3033-3232-31312f766863 | 9 |
340 | 32013030-2d30-3033-3532-32393f07fdc6 | 8 |
Now, let's merge this redzone data in to our original table.
receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | |
---|---|---|---|---|---|---|---|
0 | 32013030-2d30-3033-3432-3836149d738d | 33.400000 | 13.00 | 120.000000 | 0.382353 | 0.535714 | 0 |
1 | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.50 | 111.166667 | 0.332879 | 0.400927 | 7 |
2 | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.50 | 123.625000 | 0.244524 | 0.414175 | 10 |
3 | 32013030-2d30-3033-3232-31312f766863 | 19.562500 | 8.75 | 92.000000 | 0.236870 | 0.287703 | 9 |
4 | 32013030-2d30-3033-3535-3932f90568c6 | 19.300000 | 8.80 | 99.000000 | 0.245506 | 0.302467 | 7 |
You can see we're missing team names and receiver player names as a result of running aggregation functions like sum and mean that don't work with string columns. Let's grab a player id table where each player's id corresponds to their team name and actual name, and then merge the data back in to our original DataFrame.
receiver_player_id | posteam | receiver_player_name | |
---|---|---|---|
0 | 32013030-2d30-3032-3231-32373ce51f62 | LV | J.Witten |
1 | 32013030-2d30-3032-3239-323176c2a1fa | ARI | L.Fitzgerald |
2 | 32013030-2d30-3032-3334-35395dc60da5 | GB | A.Rodgers |
3 | 32013030-2d30-3032-3335-3030dd77cad3 | NYJ | F.Gore |
4 | 32013030-2d30-3032-3336-3832b8755c76 | MIA | R.Fitzpatrick |
receiver_player_name | posteam | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | |
---|---|---|---|---|---|---|---|---|---|
0 | R.James | SF | 32013030-2d30-3033-3432-3836149d738d | 33.400000 | 13.00 | 120.000000 | 0.382353 | 0.535714 | 0 |
1 | D.Adams | GB | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.50 | 111.166667 | 0.332879 | 0.400927 | 7 |
2 | D.Metcalf | SEA | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.50 | 123.625000 | 0.244524 | 0.414175 | 10 |
3 | T.Lockett | SEA | 32013030-2d30-3033-3232-31312f766863 | 19.562500 | 8.75 | 92.000000 | 0.236870 | 0.287703 | 9 |
4 | T.Fulgham | PHI | 32013030-2d30-3033-3535-3932f90568c6 | 19.300000 | 8.80 | 99.000000 | 0.245506 | 0.302467 | 7 |
Let's quickly rename some columns after proceeding once again.
Receiver | Team | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | |
---|---|---|---|---|---|---|---|---|---|
0 | R.James | SF | 32013030-2d30-3033-3432-3836149d738d | 33.400000 | 13.00 | 120.000000 | 0.382353 | 0.535714 | 0 |
1 | D.Adams | GB | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.50 | 111.166667 | 0.332879 | 0.400927 | 7 |
2 | D.Metcalf | SEA | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.50 | 123.625000 | 0.244524 | 0.414175 | 10 |
3 | T.Lockett | SEA | 32013030-2d30-3033-3232-31312f766863 | 19.562500 | 8.75 | 92.000000 | 0.236870 | 0.287703 | 9 |
4 | T.Fulgham | PHI | 32013030-2d30-3033-3535-3932f90568c6 | 19.300000 | 8.80 | 99.000000 | 0.245506 | 0.302467 | 7 |
In the cell below, we're doing two things. First we're calculating average WOPR, or weighted opportunity rating for each player, which is a weighted average of target share and air yards share. I talk about WOPR in previous posts.
Secondly, you can see in the table above that Richie James is the top receiver in terms of fantasy points per game. This may be true, but we don't want Richie James at the top of our table considering he's only had one big game and SF may be getting back some receivers in week 10, further limiting his value. In short, we want to make sure James is not at the top of the table by adding a total_fpts scored column to our DataFrame and then sorting the table in descending order via that column. For now, we are going to sort the table, but the table will come out of order again once we actually merge some additional tables. We'll sort again later.
Receiver | Team | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | Avg. WOPR | total_fpts | |
---|---|---|---|---|---|---|---|---|---|---|---|
5 | T.Kelce | KC | 32013030-2d30-3033-3035-3036654ef292 | 18.988889 | 8.888889 | 67.000000 | 0.233923 | 0.230771 | 7 | 0.512424 | 170.9 |
2 | D.Metcalf | SEA | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.500000 | 123.625000 | 0.244524 | 0.414175 | 10 | 0.656708 | 169.8 |
1 | D.Adams | GB | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.500000 | 111.166667 | 0.332879 | 0.400927 | 7 | 0.779968 | 168.5 |
10 | T.Hill | KC | 32013030-2d30-3033-3330-3430e890f1ff | 18.111111 | 8.000000 | 110.444444 | 0.220912 | 0.383002 | 8 | 0.599469 | 163.0 |
11 | S.Diggs | BUF | 32013030-2d30-3033-3135-383848cdfbb6 | 18.033333 | 10.111111 | 107.666667 | 0.303287 | 0.384180 | 5 | 0.723857 | 162.3 |
I said in the beginning of this post that we'll also be adding player headshots, team logos, and some styling to make our DataFrame a bit more applealing to the eye.
We can quickly load in roster data and team logo data using the two functions below from the nfl module.
team_abbr | team_name | team_id | team_nick | team_color | team_color2 | team_color3 | team_color4 | team_logo_wikipedia | team_logo_espn | |
---|---|---|---|---|---|---|---|---|---|---|
0 | ARI | Arizona Cardinals | 3800 | Cardinals | #97233f | #000000 | #ffb612 | #a5acaf | https://upload.wikimedia.org/wikipedia/en/thum... | https://a.espncdn.com/i/teamlogos/nfl/500/ari.png |
teamPlayers.gsisId | teamPlayers.headshot_url | |
---|---|---|
53064 | 00-0034422 | http://static.nfl.com/static/content/public/st... |
First, let's merge player headshots. Unfortunately, player headshot data is only available for players who played in 2019. We are going to come up with an alternative solution for rookies.
Before we actually merge the data, we have to convert the receiver_player_id's to a new ID format called gsis_id which will allow us a common column between the tables. I've added a utility function within nflfastpy that allows us to do this.
Receiver | Team | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | Avg. WOPR | total_fpts | gsis_id | teamPlayers.headshot_url | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | T.Kelce | KC | 32013030-2d30-3033-3035-3036654ef292 | 18.988889 | 8.888889 | 67.000000 | 0.233923 | 0.230771 | 7 | 0.512424 | 170.9 | 00-0030506 | http://static.nfl.com/static/content/public/st... |
1 | D.Metcalf | SEA | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.500000 | 123.625000 | 0.244524 | 0.414175 | 10 | 0.656708 | 169.8 | 00-0035640 | http://static.nfl.com/static/content/public/st... |
2 | D.Adams | GB | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.500000 | 111.166667 | 0.332879 | 0.400927 | 7 | 0.779968 | 168.5 | 00-0031381 | http://static.nfl.com/static/content/public/st... |
3 | T.Hill | KC | 32013030-2d30-3033-3330-3430e890f1ff | 18.111111 | 8.000000 | 110.444444 | 0.220912 | 0.383002 | 8 | 0.599469 | 163.0 | 00-0033040 | http://static.nfl.com/static/content/public/st... |
4 | S.Diggs | BUF | 32013030-2d30-3033-3135-383848cdfbb6 | 18.033333 | 10.111111 | 107.666667 | 0.303287 | 0.384180 | 5 | 0.723857 | 162.3 | 00-0031588 | http://static.nfl.com/static/content/public/st... |
Let's write a function that says if a player's headshot does not exist (they are a rookie), then format their headshot as a default player headshot via the URL within the function below.
We are going to be converting these headshots to HTML images.
Receiver | Team | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | Avg. WOPR | total_fpts | gsis_id | teamPlayers.headshot_url | Headshot | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | T.Kelce | KC | 32013030-2d30-3033-3035-3036654ef292 | 18.988889 | 8.888889 | 67.000000 | 0.233923 | 0.230771 | 7 | 0.512424 | 170.9 | 00-0030506 | http://static.nfl.com/static/content/public/st... | <img src="http://static.nfl.com/static/content... |
1 | D.Metcalf | SEA | 32013030-2d30-3033-3536-343097915ff1 | 21.225000 | 8.500000 | 123.625000 | 0.244524 | 0.414175 | 10 | 0.656708 | 169.8 | 00-0035640 | http://static.nfl.com/static/content/public/st... | <img src="http://static.nfl.com/static/content... |
2 | D.Adams | GB | 32013030-2d30-3033-3133-383188f79eec | 28.083333 | 11.500000 | 111.166667 | 0.332879 | 0.400927 | 7 | 0.779968 | 168.5 | 00-0031381 | http://static.nfl.com/static/content/public/st... | <img src="http://static.nfl.com/static/content... |
3 | T.Hill | KC | 32013030-2d30-3033-3330-3430e890f1ff | 18.111111 | 8.000000 | 110.444444 | 0.220912 | 0.383002 | 8 | 0.599469 | 163.0 | 00-0033040 | http://static.nfl.com/static/content/public/st... | <img src="http://static.nfl.com/static/content... |
4 | S.Diggs | BUF | 32013030-2d30-3033-3135-383848cdfbb6 | 18.033333 | 10.111111 | 107.666667 | 0.303287 | 0.384180 | 5 | 0.723857 | 162.3 | 00-0031588 | http://static.nfl.com/static/content/public/st... | <img src="http://static.nfl.com/static/content... |
Let's do the same thing with team logos. Luckily, all team logos are available, so we won't have to default to an alternative solution for missing values like we did above.
Receiver | Team | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | Avg. WOPR | ... | Headshot | team_name | team_id | team_nick | team_color | team_color2 | team_color3 | team_color4 | team_logo_wikipedia | team_logo_espn | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | T.Kelce | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3035-3036654ef292 | 18.988889 | 8.888889 | 67.000000 | 0.233923 | 0.230771 | 7 | 0.512424 | ... | <img src="http://static.nfl.com/static/content... | Kansas City Chiefs | 2310 | Chiefs | #e31837 | #ffb612 | #000000 | #e31837 | https://upload.wikimedia.org/wikipedia/en/thum... | https://a.espncdn.com/i/teamlogos/nfl/500/kc.png |
1 | T.Hill | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3330-3430e890f1ff | 18.111111 | 8.000000 | 110.444444 | 0.220912 | 0.383002 | 8 | 0.599469 | ... | <img src="http://static.nfl.com/static/content... | Kansas City Chiefs | 2310 | Chiefs | #e31837 | #ffb612 | #000000 | #e31837 | https://upload.wikimedia.org/wikipedia/en/thum... | https://a.espncdn.com/i/teamlogos/nfl/500/kc.png |
2 | M.Hardman | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3531-343087bd8daf | 9.188889 | 3.777778 | 24.222222 | 0.097382 | 0.083855 | 0 | 0.204772 | ... | <img src="http://static.nfl.com/static/content... | Kansas City Chiefs | 2310 | Chiefs | #e31837 | #ffb612 | #000000 | #e31837 | https://upload.wikimedia.org/wikipedia/en/thum... | https://a.espncdn.com/i/teamlogos/nfl/500/kc.png |
3 | C.Edwards-Helaire | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3633-3630b28b4868 | 6.266667 | 4.777778 | 1.888889 | 0.130025 | 0.001534 | 0 | 0.196112 | ... | <img src="https://sportsfly.cbsistatic.com/bun... | Kansas City Chiefs | 2310 | Chiefs | #e31837 | #ffb612 | #000000 | #e31837 | https://upload.wikimedia.org/wikipedia/en/thum... | https://a.espncdn.com/i/teamlogos/nfl/500/kc.png |
4 | S.Watkins | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3133-32353107e672 | 11.040000 | 5.800000 | 42.200000 | 0.165896 | 0.199569 | 2 | 0.388542 | ... | <img src="http://static.nfl.com/static/content... | Kansas City Chiefs | 2310 | Chiefs | #e31837 | #ffb612 | #000000 | #e31837 | https://upload.wikimedia.org/wikipedia/en/thum... | https://a.espncdn.com/i/teamlogos/nfl/500/kc.png |
5 rows × 23 columns
Let's filter out some columns since our DataFrame got pretty messy when we started merging everything toghther.
Receiver | Team | receiver_player_id | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | Avg. WOPR | total_fpts | Headshot | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | T.Kelce | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3035-3036654ef292 | 18.988889 | 8.888889 | 67.000000 | 0.233923 | 0.230771 | 7 | 0.512424 | 170.9 | <img src="http://static.nfl.com/static/content... |
1 | T.Hill | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3330-3430e890f1ff | 18.111111 | 8.000000 | 110.444444 | 0.220912 | 0.383002 | 8 | 0.599469 | 163.0 | <img src="http://static.nfl.com/static/content... |
2 | M.Hardman | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3531-343087bd8daf | 9.188889 | 3.777778 | 24.222222 | 0.097382 | 0.083855 | 0 | 0.204772 | 82.7 | <img src="http://static.nfl.com/static/content... |
3 | C.Edwards-Helaire | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3633-3630b28b4868 | 6.266667 | 4.777778 | 1.888889 | 0.130025 | 0.001534 | 0 | 0.196112 | 56.4 | <img src="https://sportsfly.cbsistatic.com/bun... |
4 | S.Watkins | <img src="https://upload.wikimedia.org/wikiped... | 32013030-2d30-3033-3133-32353107e672 | 11.040000 | 5.800000 | 42.200000 | 0.165896 | 0.199569 | 2 | 0.388542 | 55.2 | <img src="http://static.nfl.com/static/content... |
Finally, our DataFrame. Here, we're creating a copy of our original DataFrame so we can alter it as a copy rather than a view. We then can use Pandas DataFrame.styling module to add dynamic styling. Here, we're highlighing min values with a red color, and adding a background gradient to both targets and target share.
Receiver | Team | Avg. Raw Fpts | Avg. Targets | Avg. Air Yards | Avg. Target Share | Avg. Air Yards Share | Redzone Looks | Avg. WOPR | |
---|---|---|---|---|---|---|---|---|---|
T.Kelce | 18.988889 | 8.888889 | 67.000000 | 0.233923 | 0.230771 | 7 | 0.512424 | ||
D.Metcalf | 21.225000 | 8.500000 | 123.625000 | 0.244524 | 0.414175 | 10 | 0.656708 | ||
D.Adams | 28.083333 | 11.500000 | 111.166667 | 0.332879 | 0.400927 | 7 | 0.779968 | ||
T.Hill | 18.111111 | 8.000000 | 110.444444 | 0.220912 | 0.383002 | 8 | 0.599469 | ||
S.Diggs | 18.033333 | 10.111111 | 107.666667 | 0.303287 | 0.384180 | 5 | 0.723857 | ||
T.Lockett | 19.562500 | 8.750000 | 92.000000 | 0.236870 | 0.287703 | 9 | 0.556698 | ||
D.Hopkins | 18.925000 | 9.500000 | 81.875000 | 0.287161 | 0.296892 | 3 | 0.638566 | ||
K.Allen | 18.887500 | 10.875000 | 88.250000 | 0.297924 | 0.300861 | 6 | 0.657488 | ||
A.Robinson | 16.244444 | 9.555556 | 99.555556 | 0.240884 | 0.300222 | 6 | 0.571482 | ||
C.Ridley | 18.112500 | 8.750000 | 124.375000 | 0.224673 | 0.355352 | 10 | 0.585755 | ||
R.Anderson | 15.700000 | 9.000000 | 88.333333 | 0.270606 | 0.384727 | 4 | 0.675218 | ||
T.McLaurin | 17.150000 | 9.750000 | 97.000000 | 0.292507 | 0.496391 | 4 | 0.786234 | ||
A.Cooper | 15.166667 | 9.222222 | 78.888889 | 0.221353 | 0.247988 | 4 | 0.505621 | ||
W.Fuller | 18.714286 | 7.428571 | 95.000000 | 0.224549 | 0.322839 | 4 | 0.562812 | ||
T.Boyd | 16.300000 | 8.500000 | 73.000000 | 0.213146 | 0.226127 | 5 | 0.478007 | ||
A.Thielen | 15.900000 | 7.500000 | 97.875000 | 0.301737 | 0.414823 | 10 | 0.742982 | ||
J.Jones | 17.828571 | 8.000000 | 89.000000 | 0.208600 | 0.275025 | 7 | 0.505418 | ||
C.Lamb | 13.500000 | 7.555556 | 77.111111 | 0.188760 | 0.253639 | 6 | 0.460687 | ||
M.Evans | 13.300000 | 6.000000 | 65.333333 | 0.157457 | 0.192331 | 8 | 0.370817 | ||
D.Moore | 13.000000 | 6.888889 | 82.555556 | 0.215062 | 0.365288 | 4 | 0.578295 | ||
A.Brown | 16.542857 | 7.428571 | 72.857143 | 0.252116 | 0.323225 | 4 | 0.604432 | ||
J.Jefferson | 14.362500 | 5.625000 | 70.500000 | 0.221461 | 0.350219 | 1 | 0.577344 | ||
D.Waller | 14.175000 | 9.000000 | 50.125000 | 0.292961 | 0.203676 | 6 | 0.582015 | ||
C.Kupp | 14.137500 | 8.875000 | 64.250000 | 0.250515 | 0.242250 | 3 | 0.545348 | ||
J.Smith-Schuster | 14.137500 | 7.250000 | 41.375000 | 0.195525 | 0.162838 | 4 | 0.407274 |
And that's it! Thank you for reading. If you have any questions regarding the code, feel free to email me at [email protected]