Ranking Fantasy Football Teams

What if the fantasy schedule were different?

Anyone who plays fantasy football knows that it feels your team would have a higher rank, if only your schedule had been different. While with actual sports, it is non-sensical to consider every team playing every other team each week, the benefit of fantasy football is our imaginations are less constrained by the realities of life.

The goal in each week of fantasy is the same: get as many points as possible. Therefore, the strategy: who you start who you sit each week, doesn’t really depend on your opponent that week. This means that, in my mind, there is a more reasonable way to say that in some sense, the hypothetical where every team plays every other teams each week is reasonable. If this were the case, then the new true ranking would be the total sum of all possible wins over all the weeks.

So, how do you remove the effect of schedule? Fortunatley, it’s quite easy! While there is 12 choose 2 = 2 66 possible pairings each week, it is easy to visualize how many wins a team would have in a given week. If a team comes in 5th place in a given week, then we know there are 7 pairings they would have won, and 4 they would have lost. This can be done for each player, and since the number of pairings are the same for each person each week, to get a total ranking, all we have to do is count up the total number of possible wins (that is, green rectangles) over the regular season!

To get the true score, you would have to calculate the total number of wins through all the weeks of fantasy

Curious if this would be easy, I decided to do it for our fantasy league! Fortunately, if a team uses the sleeper app, this is very easy to calculate using their public api. All you need to calclate the true rankings is the league id number. The code to calculate it is shown here!

Calculating true ranks for our team

First, we need to get points for each team through all the weeks

Users Team Names Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7 Week 8 Week 9 Week 10 Week 11 Week 12 Week 13
richtowne Two RBs, One IR'd Kupp 82.56 116.44 125.78 70.42 120.02 129.14 113.36 112.88 112.8 123.98 99.74 110.4 112.08
thrgrimm Roll Up The Grimm To Win 89.44 90.34 125.86 86.72 144.7 121.14 128.48 144.68 101.4 105.5 115.98 132.76 135.24
sleepypeepy Super Lamario 101.86 129.58 130.48 135.34 124.64 152.32 122.58 166.38 102.18 129.22 129.46 122.48 140.06
gcalphonce Blowbert The Hedgehog 109.18 100.46 155.96 150.48 135.32 120.48 134.04 113.76 111.62 103.58 102.2 119.32 147.0
novasolo Van Jalen 110.3 110.72 126.28 134.56 96.12 96.6 119.66 116.76 121.68 108.82 123.8 136.4 165.02
bigdaddynacho Hi-T: Power of the Run 111.88 136.82 115.54 132.3 89.78 127.34 144.86 158.06 114.68 122.66 99.42 79.4 128.26
garretthaima No Name! 115.16 135.4 144.26 158.52 131.06 103.96 120.9 108.2 138.3 130.34 102.64 176.86 121.16
accassid Widest right 126.04 185.66 128.28 156.32 115.04 120.54 150.76 169.9 122.5 191.72 158.88 130.32 127.9
jjprzyby Fields The Burn 128.04 145.24 158.36 157.0 172.52 126.72 142.84 127.2 130.66 113.64 146.16 157.78 154.16
troyathy Wet Bass Pussy 136.24 182.56 213.48 142.1 98.76 114.46 109.7 127.46 139.82 175.08 168.8 170.46 104.8
partyoverhere Dick Gouraige 139.22 122.3 116.06 105.86 125.36 129.54 114.82 151.56 104.86 134.86 93.66 158.74 134.16
lilmaz Kicker? What about Dicker 140.26 148.8 140.5 118.38 128.66 146.68 140.36 165.42 116.14 198.52 156.7 124.58 142.58

Then we can convert these point values to number of wins for that week and add up the total number of wins.

User Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7 Week 8 Week 9 Week 10 Week 11 Week 12 Week 13 Total Wins
jjprzyby 8 8 10 10 11 6 9 4 9 3 8 8 10 104
lilmaz 11 9 7 3 7 10 8 9 6 11 9 4 8 102
accassid 7 11 5 9 3 4 11 11 8 10 10 5 3 97
troyathy 9 10 11 7 2 2 0 5 11 9 11 10 0 87
garretthaima 6 6 8 11 8 1 4 0 10 7 4 11 2 78
sleepypeepy 2 5 6 6 5 11 5 10 1 6 7 3 7 74
partyoverhere 10 4 1 2 6 9 2 7 2 8 0 9 5 65
gcalphonce 3 1 9 8 9 3 7 2 3 0 3 2 9 59
novasolo 4 2 4 5 1 0 3 3 7 2 6 7 11 55
bigdaddynacho 5 7 0 4 0 7 10 8 5 4 1 0 4 55
thrgrimm 1 0 3 1 10 5 6 6 0 1 5 6 6 50
richtowne 0 3 2 0 4 8 1 1 4 5 2 1 1 32

Finally, we have the true rankings.

Code to generate results

Note, this code does not have pretty formatting.

import pandas as pd
import requests as rq
from tqdm import tqdm

league_id = '978044540609208320'  # 3rd Shitshow
bn = 'https://api.sleeper.app/v1' # Base name


# Get usernames
r = rq.get(f'{bn}/league/{league_id}/rosters')
t = r.json()
ownerIDs = [k['owner_id'] for k in t]
users = []
for k in tqdm(ownerIDs):
    r = rq.get(f'{bn}/user/{k}')
    users.append(r.json()['username'])

# Get team names
r = rq.get(f'{bn}/league/{league_id}/users')
t = r.json()
teamNames = 12*['No Name!']
for k in t:
    idx = ownerIDs.index(k['user_id'])
    if 'team_name' in k['metadata']:
        teamNames[idx] = k['metadata']['team_name']


# Grab points from each week
df = {'Users':users, 'Team Names':teamNames}
for week in tqdm(range(1,11)):
    r = rq.get(f'{bn}/league/{league_id}/matchups/{week}')
    if r.status_code == 200:
        data = r.json()
        points = [k['points'] for k in data]
        df[f'Week {week}'] = points
df = pd.DataFrame(df)
df_ranked = df.rank(numeric_only=True) - 1


# Convert scores to ranks!
df_ranked['Total Wins'] = df_ranked.sum(numeric_only=True,axis=1)
df_ranked.insert(loc=0,column='User',value=users)
df_ranked = df_ranked.sort_values(by='Total Wins',ascending=False)

print('Point Totals'); print(df)
print('Total Wins'); print(df_ranked)

Thank you for reading!