If you have any questions about the code here, feel free to reach out to us on Twitter or on Reddit.

Shameless Plug Section

If you like Fantasy Football and have an interest in learning how to code, check out our Ultimate Guide on Learning Python with Fantasy Football Online Course. Here is a link to purchase for 15% off. The course includes 15 chapters of material, 14 hours of video, hundreds of data sets, lifetime updates, and a Slack channel invite to join the Fantasy Football with Python community.

Fantasy Football League History

In this part of the intermediate series we'll be diving into researching and analyzing fantasy football league history data. If you're like me, being in a fantasy football league for nearly a decade means the competition is fierce. Our league does our best remembering what happened in years past to retain bragging rights, but there must be a better way to keep track of it all. This post will go into how we can use the ESPN API to pull league history data (teams, years, scores, matchups) to create a running record of your league.

It turns out, ESPN has an API with everything recorded assuming you stuck with the same league and reactivated it each year. Each team has a unique id tied to it that we can use pull individual matchups, scores, players, etc. I will show a few examples of what we can do with this data and how we can explore it, but the applications are endless. My leaguemates pointed out it would be especially interesting to look at total points for / against and head to head matchup records. Today I will show you how to obtain total league records and points for / against.

Pulling the Data from ESPN API

Setup

The first step is always setup. Let's import the necessary packages and write up a small function that will be used in calculating wins in our main code block.

Single Season Pull

This code block sets us up to pull win/loss record, points for, and points against data for a given year. A general flow of this block of code is as follows. First we connect to the API and pull data for the specified year. We are interested in total league history, so if for example you have a league that has run for five year then you must make 5 separate API calls to get the total history, one for each year (this is the next step). An important note is the data we are pulling from ESPN is in json format. To transform this into a pandas dataframe we must "unroll" the json data. Often times this gets a bit messy and it is important to have your data in the best format for the rest of the planned analysis. So this is an important step that helps you set up the rest of the notebook. This "unrolling" will be glossed over but if you are interested in this feel free to buy the course or reach out. Once we have the data in the format we desire we then, for each weekly matchup, calculate win margins and sum these for each unique team. Next we go about getting point totals and then merge these two dataframes together on team id. We are then left with a single dataframe that contains records, points for, points against, and draft order for a singular year.

All you have to do to run this code on your own is change the league_id to your own league id. I found my league id by looking in the url on the home page of the ESPN league I wanted to analyze. The url also tells you the team id when you visit a specific teams page if you are interested in pulling data for a specific franchise. The ESPN API endpoints we are using today is

This allows us to enter league id and the year we are interested in obtaining season data for. Lets take a look at the code.

This next cell uses the function defined above to get data for each year of the fantasy league. I also added in the draft order since I thought it would be interesting if the high picks always resulted in better records. This would be an interesting analysis to dive deeper into next time. In my league, we actually had a tie back in 2014 so I wrote an extra line to deal with this. Feel free to disregard ties, or add it in later if need be. Let's see what one year of our league history data looks like!

Team ID Year W L Tie Points For Points Allowed Pick Number
1 5 2014 10.0 5.0 0.0 1730.0 1463.0 7
8 7 2014 9.0 6.0 0.0 1687.0 1691.0 4
7 8 2014 9.0 6.0 0.0 1672.0 1475.0 5
3 4 2014 8.0 7.0 0.0 1547.0 1604.0 1
4 9 2014 8.0 6.0 1.0 1461.0 1484.0 8
2 10 2014 8.0 7.0 0.0 1553.0 1472.0 10
5 2 2014 7.0 8.0 0.0 1541.0 1630.0 6
9 6 2014 7.0 8.0 0.0 1462.0 1444.0 9
0 1 2014 6.0 8.0 1.0 1578.0 1593.0 3
6 3 2014 2.0 13.0 0.0 1251.0 1626.0 2

2014 was the first year of my league. Its nice to see that the team with the most points (team 5) had the most wins and the team with the least points (team 3) had the most losses. This is what you would expect but is not always the case. Draft order shows that pick 2 and 3 ended up getting 9th and 10th place.

Pull and Combine All Seasons

Now that we have the data pulling process down for one year we can run this over the years our league has been active and group it together to get some insightful league history totals! This will reveal the true best player in your league! To do this we initialize a dataframe with the league start year, then populate and concatenate with all the following years. After getting all our years into one dataframe we can group by team id to get totals for each franchise.

Our totals dataframe, league_his_tot, contains every year and record for every team in it, as well as the number of points they scored / allowed that year. This is chalked full of information. The first thing we can do it use groupby to sum up total number of wins and total number of points for / against in league history. Did you make it to the top of the leaderboard?

Team ID W L Tie Points For Total Points Allowed Total
0 1 63.0 44.0 1.0 11348.4 11093.5
3 4 60.0 48.0 0.0 11407.4 11217.6
4 5 57.0 51.0 0.0 11410.0 11201.1
1 2 55.0 53.0 0.0 11139.1 11064.1
6 7 55.0 53.0 0.0 10860.5 11238.9
7 8 55.0 53.0 0.0 10989.6 10605.7
2 3 54.0 54.0 0.0 11036.0 11233.2
5 6 50.0 58.0 0.0 10762.0 10644.9
8 9 45.0 62.0 1.0 10504.8 10948.2
9 10 45.0 63.0 0.0 10864.3 11074.9

This dataframe shows the total wins and loses for each franchise along with their points scored and allowed. This was fun information to share with my leaguemates and I hope you find the same. It will definitely be referred back to and updated every year for my league. There are still many possibilities for this dataset. Next time we will check out the head to head records. We will also tie up some loose ends such as implementing team names and showing rosters for any given team or year.