FantasyCalc.com Intro

Hey FDP readers! I'm Josh from FantasyCalc.com. I've learned Python, R, Angular, SQL, AWS, and a whole lot more working on my fantasy football website over the past few years, so I'm excited to have the opportunity to collaborate by guest writing an article here.

FantasyCalc uses an algorithm to calculate player trade value from almost 1 million real fantasy football trades. In this article, we're going to compare those values to ADP to find over/undervalued players.

What do I need to know?

You should be familiar with lists, maps, and for loops from the first three intro to python articles. In this project, we'll cover APIs and JSON, and how we can combine multiple data sources for data analysis.

Application Program Interface (API) are how websites interact with backend databases and servers to get data. The APIs we're going to use return data in the JSON format - a common human readable response format consisting of strings, numbers, maps and lists. We're going to use two in this article:

FantasyCalc.com's player value API

FantasyFootballCalculator's ADP API

If you click on the FantasyCalc link, you'll see what JSON data looks like. Websites use HTML and CSS to turn JSON data into something that looks much prettier for human consumption. For example, the FantasyCalc API is the exact same API that powers the rankings.

Let's get started!

First, we'll want to import the data from the external APIs. We can do this using the requests library. Let's import it and tell Python to expect JSON data.

import requests

trade_values = requests.get("https://api.fantasycalc.com/values/current?isDynasty=false&numQbs=1&numTeams=12&ppr=1").json()
adp = requests.get("https://fantasyfootballcalculator.com/api/v1/adp/standard?teams=12&year=2023").json()

trade_values[0]
{'player': {'id': 7569,
  'name': 'Justin Jefferson',
  'mflId': '14836',
  'sleeperId': '6794',
  'position': 'WR',
  'maybeBirthday': '1999-06-16',
  'maybeHeight': '73',
  'maybeWeight': 195,
  'maybeCollege': 'LSU',
  'maybeTeam': 'MIN',
  'maybeAge': 24.082668278253426,
  'maybeYoe': 3},
 'value': 10726,
 'overallRank': 1,
 'positionRank': 1,
 'trend30Day': -144,
 'redraftDynastyValueDifference': 0,
 'redraftDynastyValuePercDifference': 0,
 'redraftValue': 10726,
 'combinedValue': 21452,
 'maybeMovingStandardDeviation': 3,
 'maybeMovingStandardDeviationPerc': 0,
 'maybeMovingStandardDeviationAdjusted': 2,
 'displayTrend': False,
 'maybeOwner': None,
 'starter': False}

More on APIs

We use a combination of path and query parameters to tell the server exactly what data we want. APIs are manually defined and will usually host documentation for how to use them. This is is too large of a topic to cover in this article, so here's an article if you'd like to learn a little more.

For now, we'll move on with our data imported.

Researching the data

We want to compare a player's ADP to their trade value. We're using two different sources with different response formats, so we'll need to figure out how we can compare them. Let's take a deeper look into the response JSON from both sites.

You can easily visualize the JSON responses in a tool like https://jsonviewer.stack.hu/.

Looking at FantasyCalc.com's player value API, we'll notice:

  • The API returns a list of players
  • Each player has a "overallRank"
  • Each player has an object called "player" with an attribute "name"
  • Now, looking at FantasyFootballCalculator's ADP API, we'll notice:

  • The response returns a Map with a key called "players"
  • Each player has a "name" and "adp" key
  • So for each player, we'll want to compare FantasyCalc's "overallRank" to FFC's "adp".

    Reformatting the data

    Now that we know which values on the JSON response we want to compare, we can reformat each source into the same format. We'll want to be able to lookup a player's ADP or trade value from their name, so we'll use the Map data structure.

    adp_map = {}
    for player in adp['players']:
        adp_map[player['name']] = player['adp']
    
    trade_values_map = {}
    for player in trade_values:
        trade_values_map[player['player']['name']] = player['overallRank']
    
    print('ADP map: ', adp_map)
    print('Trade value map: ', trade_values_map)
    ADP map:  {'Christian McCaffrey': 1.3, 'Austin Ekeler': 2.0, 'Jonathan Taylor': 2.7, 'Justin Jefferson': 3.7, 'Saquon Barkley': 3.9, "Ja'Marr Chase": 6.4, 'Kenneth Walker III': 6.8, 'Nick Chubb': 7.8, 'Josh Jacobs': 7.9, 'Travis Kelce': 9.5, 'Derrick Henry': 9.7, 'Tony Pollard': 11.9, 'Travis Etienne': 12.3, 'Tyreek Hill': 12.9, 'Cooper Kupp': 13.8, 'Breece Hall': 15.6, 'Davante Adams': 16.3, 'Bijan Robinson': 17.4, 'CeeDee Lamb': 17.7, 'Stefon Diggs': 18.1, 'Najee Harris': 19.0, 'A.J. Brown': 19.2, 'George Kittle': 23.8, 'Jaylen Waddle': 23.8, 'Mark Andrews': 24.5, 'Dalvin Cook': 24.7, 'Rhamondre Stevenson': 25.4, 'Amon-Ra St. Brown': 26.3, 'Garrett Wilson': 28.1, 'Tee Higgins': 29.0, 'J.K. Dobbins': 29.6, 'Josh Allen': 29.8, 'Patrick Mahomes': 30.8, 'Chris Olave': 31.6, 'DeVonta Smith': 31.7, 'Aaron Jones': 33.1, 'Calvin Ridley': 34.3, 'Deebo Samuel': 37.0, 'Cam Akers': 38.6, 'D.K. Metcalf': 38.9, 'Amari Cooper': 39.5, 'T.J. Hockenson': 39.9, 'Jalen Hurts': 41.0, 'Miles Sanders': 41.2, 'Christian Watson': 41.8, 'Dameon Pierce': 42.4, 'D.J. Moore': 43.3, 'Joe Burrow': 47.0, 'Keenan Allen': 47.2, 'Kyle Pitts': 47.7, 'Terry McLaurin': 47.7, "D'Andre Swift": 48.7, 'David Montgomery': 48.9, 'Joe Mixon': 50.4, 'Mike Williams': 52.4, 'Jerry Jeudy': 53.4, 'Isiah Pacheco': 54.2, 'Tyler Lockett': 56.0, 'Justin Fields': 56.2, 'Dallas Goedert': 58.4, 'DeAndre Hopkins': 59.3, 'Lamar Jackson': 60.0, 'Tyler Allgeier': 60.1, 'Jameson Williams': 60.6, 'Drake London': 62.0, 'James Conner': 62.4, 'Darren Waller': 62.5, 'Justin Herbert': 65.6, 'Mike Evans': 66.0, 'Brandon Aiyuk': 68.0, 'Christian Kirk': 68.7, 'Brian Robinson Jr.': 70.1, 'Trevor Lawrence': 70.3, 'Chris Godwin': 71.2, 'Alvin Kamara': 71.5, 'Javonte Williams': 73.0, 'Jamaal Williams': 75.3, 'George Pickens': 75.6, 'Jahan Dotson': 75.7, 'Michael Pittman Jr.': 76.2, 'Dak Prescott': 77.0, 'A.J. Dillon': 78.6, 'Rashaad Penny': 78.9, 'Rashod Bateman': 79.9, 'Pat Freiermuth': 81.9, 'Treylon Burks': 83.8, 'James Cook': 84.5, 'Marquise Brown': 84.9, 'Gabriel Davis': 85.1, 'Rachaad White': 85.3, 'Evan Engram': 86.6, 'Deshaun Watson': 87.5, 'Kadarius Toney': 88.6, 'Courtland Sutton': 90.0, 'Kirk Cousins': 91.4, 'David Njoku': 92.3, 'Damien Harris': 93.1, 'Alexander Mattison': 93.3, 'Tua Tagovailoa': 94.5, 'Diontae Johnson': 94.7, 'Daniel Jones': 95.6, 'Donta Foreman': 98.4, 'Elijah Mitchell': 99.6, 'Brandin Cooks': 100.7, 'Jakobi Meyers': 101.2, 'Antonio Gibson': 103.2, 'Michael Thomas': 104.9, 'JuJu Smith-Schuster': 105.1, 'Geno Smith': 106.6, 'Jared Goff': 107.6, 'Aaron Rodgers': 107.9, 'Cole Kmet': 109.0, 'Darnell Mooney': 110.5, 'Ezekiel Elliott': 110.6, 'Jahmyr Gibbs': 112.6, 'Kenneth Gainwell': 113.8, 'Raheem Mostert': 114.1, 'Dalton Schultz': 114.4, 'Elijah Moore': 114.6, 'Russell Wilson': 115.0, 'Devin Singletary': 116.1, 'Dawson Knox': 117.1, 'Allen Lazard': 118.7, 'Samaje Perine': 119.1, 'San Francisco Defense': 120.8, 'Donovan Peoples-Jones': 121.3, 'Cordarrelle Patterson': 121.5, 'Zay Jones': 121.5, 'Tyler Boyd': 121.7, 'Kareem Hunt': 123.8, 'Nico Collins': 123.8, 'Chigoziem Okonkwo': 123.8, 'Michael Mayer': 123.9, 'Greg Dulcich': 124.0, 'Jerick McKinnon': 124.7, 'Buffalo Defense': 125.9, 'Dallas Defense': 128.2, 'Adam Thielen': 129.3, 'Derek Carr': 130.8, 'Leonard Fournette': 132.4, 'Chuba Hubbard': 132.8, 'Rondale Moore': 134.7, 'Taysom Hill': 135.1, 'Justin Tucker': 136.3, 'Jaxon Smith-Njigba': 136.4, 'Denver Defense': 137.6, 'Philadelphia Defense': 138.0, 'Tyler Bass': 140.2, 'Trey Lance': 140.5, 'Dalton Kincaid': 140.8, 'John Metchie III': 141.2, 'Kyler Murray': 142.2, 'Matthew Stafford': 142.8, 'New England Defense': 143.4, 'Harrison Butker': 143.5, 'Daniel Carlson': 143.5, 'Tampa Bay Defense': 143.8, 'Clyde Edwards-Helaire': 144.1, 'Kenny Pickett': 144.3, 'Quentin Johnston': 144.4, 'Jaylen Warren': 144.4, 'Gerald Everett': 145.0, 'Zach Ertz': 145.9, 'Zach Charbonnet': 146.1, 'Baltimore Defense': 146.3, 'Jordan Addison': 146.9, 'Zamir White': 147.2, 'Mike Gesicki': 147.3, 'Anthony Richardson': 147.7, 'Zay Flowers': 150.2, 'Skyy Moore': 150.6, 'Michael Gallup': 151.4, 'Kansas City Defense': 153.3, "Wan'Dale Robinson": 154.6, 'Nick Folk': 155.8, 'Younghoe Koo': 156.1, 'Gus Edwards': 156.8, 'Romeo Doubs': 157.8, 'Jimmy Garoppolo': 157.9, 'Alec Pierce': 158.0, 'Sean Tucker': 158.3, 'Jordan Love': 158.9, 'Michael Carter': 159.3, 'Tyler Higbee': 159.4, 'Pittsburgh Defense': 159.4, 'James Robinson': 160.4, 'New Orleans Defense': 160.5, 'Devon Achane': 160.8, 'Miami Defense': 161.0, 'Hunter Renfrow': 161.7, 'Jason Sanders': 161.9, 'Jerome Ford': 162.8, 'Cincinnati Defense': 162.9, 'Brock Purdy': 163.3, 'K.J. Osborn': 163.6, 'Brandon McManus': 167.7, 'Matt Gay': 169.3, 'Mecole Hardman': 169.6, 'Graham Gano': 171.9, 'Wil Lutz': 172.6, 'Jake Elliott': 173.7, 'Jason Myers': 174.5, 'Greg Joseph': 176.2}
    Trade value map:  {'Justin Jefferson': 1, 'Christian McCaffrey': 2, "Ja'Marr Chase": 3, 'Bijan Robinson': 4, 'Cooper Kupp': 5, 'Austin Ekeler': 6, 'Travis Kelce': 7, 'A.J. Brown': 8, 'Jonathan Taylor': 9, 'CeeDee Lamb': 10, 'Nick Chubb': 11, 'Patrick Mahomes': 12, 'Saquon Barkley': 13, 'Stefon Diggs': 14, 'Tyreek Hill': 15, 'Derrick Henry': 16, 'Josh Jacobs': 17, 'Garrett Wilson': 18, 'Jaylen Waddle': 19, 'Josh Allen': 20, 'Tony Pollard': 21, 'Davante Adams': 22, 'Amon-Ra St. Brown': 23, 'Breece Hall': 24, 'Rhamondre Stevenson': 25, 'Jalen Hurts': 26, 'Chris Olave': 27, 'Travis Etienne': 28, 'DK Metcalf': 29, 'Jahmyr Gibbs': 30, 'Tee Higgins': 31, 'Kenneth Walker': 32, 'Mark Andrews': 33, 'Najee Harris': 34, 'Miles Sanders': 35, 'DeVonta Smith': 36, 'Joe Burrow': 37, 'Deebo Samuel': 38, 'Lamar Jackson': 39, 'Trevor Lawrence': 40, 'Joe Mixon': 41, 'Aaron Jones': 42, 'Justin Herbert': 43, 'DJ Moore': 44, 'Terry McLaurin': 45, 'J.K. Dobbins': 46, 'Dalvin Cook': 47, 'Calvin Ridley': 48, 'Alvin Kamara': 49, "D'Andre Swift": 50, 'Justin Fields': 51, 'Javonte Williams': 52, 'Drake London': 53, 'Brandon Aiyuk': 54, 'Chris Godwin': 55, 'Amari Cooper': 56, 'DeAndre Hopkins': 57, 'Keenan Allen': 58, 'George Kittle': 59, 'David Montgomery': 60, 'Jerry Jeudy': 61, 'Michael Pittman': 62, 'Jaxon Smith-Njigba': 63, 'Cam Akers': 64, 'Dameon Pierce': 65, 'Diontae Johnson': 66, 'Rachaad White': 67, 'Deshaun Watson': 68, 'James Conner': 69, 'Christian Watson': 70, 'Christian Kirk': 71, 'Marquise Brown': 72, 'Mike Evans': 73, 'Alexander Mattison': 74, 'Treylon Burks': 75, 'Anthony Richardson': 76, 'Jahan Dotson': 77, 'T.J. Hockenson': 78, 'Dallas Goedert': 79, 'Darren Waller': 80, 'Mike Williams': 81, 'Zach Charbonnet': 82, 'Jameson Williams': 83, 'Quentin Johnston': 84, 'Tyler Lockett': 85, 'Jordan Addison': 86, 'Bryce Young': 87, 'Zay Flowers': 88, 'Kyler Murray': 89, 'Kyle Pitts': 90, 'Antonio Gibson': 91, 'Devon Achane': 92, 'AJ Dillon': 93, 'Samaje Perine': 94, 'Dak Prescott': 95, 'James Cook': 96, 'Isiah Pacheco': 97, 'Rashaad Penny': 98, 'George Pickens': 99, 'Jamaal Williams': 100, 'Khalil Herbert': 101, 'Jerick McKinnon': 102, 'Tua Tagovailoa': 103, 'C.J. Stroud': 104, 'Ezekiel Elliott': 105, 'Daniel Jones': 106, 'Michael Thomas': 107, 'Kadarius Toney': 108, 'Brian Robinson': 109, 'Odell Beckham': 110, 'Courtland Sutton': 111, 'Brandin Cooks': 112, 'Elijah Mitchell': 113, 'Dalton Kincaid': 114, 'Damien Harris': 115, 'Rashod Bateman': 116, 'JuJu Smith-Schuster': 117, 'Kendre Miller': 118, 'Devin Singletary': 119, 'Tyler Allgeier': 120, 'Allen Lazard': 121, 'Gabe Davis': 122, 'Jakobi Meyers': 123, 'Skyy Moore': 124, 'Jared Goff': 125, 'Evan Engram': 126, 'Roschon Johnson': 127, 'Elijah Moore': 128, 'Aaron Rodgers': 129, 'Adam Thielen': 130, 'Kirk Cousins': 131, 'Russell Wilson': 132, 'Jaylen Warren': 133, 'Tank Bigsby': 134, 'Jonathan Mingo': 135, 'Jordan Love': 136, "D'Onta Foreman": 137, 'David Njoku': 138, 'Kareem Hunt': 139, 'Darnell Mooney': 140}
    

    Comparing the data

    Now we have both data sources in the same format, we can easily compare the two. Let's loop over the trades values, and use the name key to get that player's trade value, and print the result.

    Note the trade values might have some different players than ADP. If we have a player in the trade values that does not have ADP data, we'll just skip them.

    for name, player_trade_value in trade_values_map.items():
        player_adp = adp_map.get(name)
    
        # Skip players without ADP data
        if player_adp is None:
            continue
    
        diff = player_trade_value - player_adp
    
        print(name, player_trade_value, player_adp, diff)
    Justin Jefferson 1 3.7 -2.7
    Christian McCaffrey 2 1.3 0.7
    Ja'Marr Chase 3 6.4 -3.4000000000000004
    Bijan Robinson 4 17.4 -13.399999999999999
    Cooper Kupp 5 13.8 -8.8
    Austin Ekeler 6 2.0 4.0
    Travis Kelce 7 9.5 -2.5
    A.J. Brown 8 19.2 -11.2
    Jonathan Taylor 9 2.7 6.3
    CeeDee Lamb 10 17.7 -7.699999999999999
    Nick Chubb 11 7.8 3.2
    Patrick Mahomes 12 30.8 -18.8
    Saquon Barkley 13 3.9 9.1
    Stefon Diggs 14 18.1 -4.100000000000001
    Tyreek Hill 15 12.9 2.0999999999999996
    Derrick Henry 16 9.7 6.300000000000001
    Josh Jacobs 17 7.9 9.1
    Garrett Wilson 18 28.1 -10.100000000000001
    Jaylen Waddle 19 23.8 -4.800000000000001
    Josh Allen 20 29.8 -9.8
    Tony Pollard 21 11.9 9.1
    Davante Adams 22 16.3 5.699999999999999
    Amon-Ra St. Brown 23 26.3 -3.3000000000000007
    Breece Hall 24 15.6 8.4
    Rhamondre Stevenson 25 25.4 -0.3999999999999986
    Jalen Hurts 26 41.0 -15.0
    Chris Olave 27 31.6 -4.600000000000001
    Travis Etienne 28 12.3 15.7
    Jahmyr Gibbs 30 112.6 -82.6
    Tee Higgins 31 29.0 2.0
    Mark Andrews 33 24.5 8.5
    Najee Harris 34 19.0 15.0
    Miles Sanders 35 41.2 -6.200000000000003
    DeVonta Smith 36 31.7 4.300000000000001
    Joe Burrow 37 47.0 -10.0
    Deebo Samuel 38 37.0 1.0
    Lamar Jackson 39 60.0 -21.0
    Trevor Lawrence 40 70.3 -30.299999999999997
    Joe Mixon 41 50.4 -9.399999999999999
    Aaron Jones 42 33.1 8.899999999999999
    Justin Herbert 43 65.6 -22.599999999999994
    Terry McLaurin 45 47.7 -2.700000000000003
    J.K. Dobbins 46 29.6 16.4
    Dalvin Cook 47 24.7 22.3
    Calvin Ridley 48 34.3 13.700000000000003
    Alvin Kamara 49 71.5 -22.5
    D'Andre Swift 50 48.7 1.2999999999999972
    Justin Fields 51 56.2 -5.200000000000003
    Javonte Williams 52 73.0 -21.0
    Drake London 53 62.0 -9.0
    Brandon Aiyuk 54 68.0 -14.0
    Chris Godwin 55 71.2 -16.200000000000003
    Amari Cooper 56 39.5 16.5
    DeAndre Hopkins 57 59.3 -2.299999999999997
    Keenan Allen 58 47.2 10.799999999999997
    George Kittle 59 23.8 35.2
    David Montgomery 60 48.9 11.100000000000001
    Jerry Jeudy 61 53.4 7.600000000000001
    Jaxon Smith-Njigba 63 136.4 -73.4
    Cam Akers 64 38.6 25.4
    Dameon Pierce 65 42.4 22.6
    Diontae Johnson 66 94.7 -28.700000000000003
    Rachaad White 67 85.3 -18.299999999999997
    Deshaun Watson 68 87.5 -19.5
    James Conner 69 62.4 6.600000000000001
    Christian Watson 70 41.8 28.200000000000003
    Christian Kirk 71 68.7 2.299999999999997
    Marquise Brown 72 84.9 -12.900000000000006
    Mike Evans 73 66.0 7.0
    Alexander Mattison 74 93.3 -19.299999999999997
    Treylon Burks 75 83.8 -8.799999999999997
    Anthony Richardson 76 147.7 -71.69999999999999
    Jahan Dotson 77 75.7 1.2999999999999972
    T.J. Hockenson 78 39.9 38.1
    Dallas Goedert 79 58.4 20.6
    Darren Waller 80 62.5 17.5
    Mike Williams 81 52.4 28.6
    Zach Charbonnet 82 146.1 -64.1
    Jameson Williams 83 60.6 22.4
    Quentin Johnston 84 144.4 -60.400000000000006
    Tyler Lockett 85 56.0 29.0
    Jordan Addison 86 146.9 -60.900000000000006
    Zay Flowers 88 150.2 -62.19999999999999
    Kyler Murray 89 142.2 -53.19999999999999
    Kyle Pitts 90 47.7 42.3
    Antonio Gibson 91 103.2 -12.200000000000003
    Devon Achane 92 160.8 -68.80000000000001
    Samaje Perine 94 119.1 -25.099999999999994
    Dak Prescott 95 77.0 18.0
    James Cook 96 84.5 11.5
    Isiah Pacheco 97 54.2 42.8
    Rashaad Penny 98 78.9 19.099999999999994
    George Pickens 99 75.6 23.400000000000006
    Jamaal Williams 100 75.3 24.700000000000003
    Jerick McKinnon 102 124.7 -22.700000000000003
    Tua Tagovailoa 103 94.5 8.5
    Ezekiel Elliott 105 110.6 -5.599999999999994
    Daniel Jones 106 95.6 10.400000000000006
    Michael Thomas 107 104.9 2.0999999999999943
    Kadarius Toney 108 88.6 19.400000000000006
    Courtland Sutton 111 90.0 21.0
    Brandin Cooks 112 100.7 11.299999999999997
    Elijah Mitchell 113 99.6 13.400000000000006
    Dalton Kincaid 114 140.8 -26.80000000000001
    Damien Harris 115 93.1 21.900000000000006
    Rashod Bateman 116 79.9 36.099999999999994
    JuJu Smith-Schuster 117 105.1 11.900000000000006
    Devin Singletary 119 116.1 2.9000000000000057
    Tyler Allgeier 120 60.1 59.9
    Allen Lazard 121 118.7 2.299999999999997
    Jakobi Meyers 123 101.2 21.799999999999997
    Skyy Moore 124 150.6 -26.599999999999994
    Jared Goff 125 107.6 17.400000000000006
    Evan Engram 126 86.6 39.400000000000006
    Elijah Moore 128 114.6 13.400000000000006
    Aaron Rodgers 129 107.9 21.099999999999994
    Adam Thielen 130 129.3 0.6999999999999886
    Kirk Cousins 131 91.4 39.599999999999994
    Russell Wilson 132 115.0 17.0
    Jaylen Warren 133 144.4 -11.400000000000006
    Jordan Love 136 158.9 -22.900000000000006
    David Njoku 138 92.3 45.7
    Kareem Hunt 139 123.8 15.200000000000003
    Darnell Mooney 140 110.5 29.5
    

    Formatting our results

    Now we have the comparison data between ADP and trade value! We'll want to sort it though, so the results show our top over/undervalued players.

    Instead of printing each row, let's add them to a list and sort the list at the end.

    diffs = []
    for name, player_trade_value in trade_values_map.items():
        player_adp = adp_map.get(name)
    
        # Skip players without ADP data
        if player_adp is None:
            continue
    
        diff = player_trade_value - player_adp
    
        diffs.append([name, player_trade_value, player_adp, diff])
    
    
    # Use a lambda to sort by the 'diff' we defined above.
    # d[3] is sorting by the 4th element of the list since lists are indexed started from zero.
    sorted_diffs = sorted(diffs, key=lambda d: d[3])
    for diff in sorted_diffs:
        print(diff)
    ['Jahmyr Gibbs', 30, 112.6, -82.6]
    ['Jaxon Smith-Njigba', 63, 136.4, -73.4]
    ['Anthony Richardson', 76, 147.7, -71.69999999999999]
    ['Devon Achane', 92, 160.8, -68.80000000000001]
    ['Zach Charbonnet', 82, 146.1, -64.1]
    ['Zay Flowers', 88, 150.2, -62.19999999999999]
    ['Jordan Addison', 86, 146.9, -60.900000000000006]
    ['Quentin Johnston', 84, 144.4, -60.400000000000006]
    ['Kyler Murray', 89, 142.2, -53.19999999999999]
    ['Trevor Lawrence', 40, 70.3, -30.299999999999997]
    ['Diontae Johnson', 66, 94.7, -28.700000000000003]
    ['Dalton Kincaid', 114, 140.8, -26.80000000000001]
    ['Skyy Moore', 124, 150.6, -26.599999999999994]
    ['Samaje Perine', 94, 119.1, -25.099999999999994]
    ['Jordan Love', 136, 158.9, -22.900000000000006]
    ['Jerick McKinnon', 102, 124.7, -22.700000000000003]
    ['Justin Herbert', 43, 65.6, -22.599999999999994]
    ['Alvin Kamara', 49, 71.5, -22.5]
    ['Lamar Jackson', 39, 60.0, -21.0]
    ['Javonte Williams', 52, 73.0, -21.0]
    ['Deshaun Watson', 68, 87.5, -19.5]
    ['Alexander Mattison', 74, 93.3, -19.299999999999997]
    ['Patrick Mahomes', 12, 30.8, -18.8]
    ['Rachaad White', 67, 85.3, -18.299999999999997]
    ['Chris Godwin', 55, 71.2, -16.200000000000003]
    ['Jalen Hurts', 26, 41.0, -15.0]
    ['Brandon Aiyuk', 54, 68.0, -14.0]
    ['Bijan Robinson', 4, 17.4, -13.399999999999999]
    ['Marquise Brown', 72, 84.9, -12.900000000000006]
    ['Antonio Gibson', 91, 103.2, -12.200000000000003]
    ['Jaylen Warren', 133, 144.4, -11.400000000000006]
    ['A.J. Brown', 8, 19.2, -11.2]
    ['Garrett Wilson', 18, 28.1, -10.100000000000001]
    ['Joe Burrow', 37, 47.0, -10.0]
    ['Josh Allen', 20, 29.8, -9.8]
    ['Joe Mixon', 41, 50.4, -9.399999999999999]
    ['Drake London', 53, 62.0, -9.0]
    ['Cooper Kupp', 5, 13.8, -8.8]
    ['Treylon Burks', 75, 83.8, -8.799999999999997]
    ['CeeDee Lamb', 10, 17.7, -7.699999999999999]
    ['Miles Sanders', 35, 41.2, -6.200000000000003]
    ['Ezekiel Elliott', 105, 110.6, -5.599999999999994]
    ['Justin Fields', 51, 56.2, -5.200000000000003]
    ['Jaylen Waddle', 19, 23.8, -4.800000000000001]
    ['Chris Olave', 27, 31.6, -4.600000000000001]
    ['Stefon Diggs', 14, 18.1, -4.100000000000001]
    ["Ja'Marr Chase", 3, 6.4, -3.4000000000000004]
    ['Amon-Ra St. Brown', 23, 26.3, -3.3000000000000007]
    ['Terry McLaurin', 45, 47.7, -2.700000000000003]
    ['Justin Jefferson', 1, 3.7, -2.7]
    ['Travis Kelce', 7, 9.5, -2.5]
    ['DeAndre Hopkins', 57, 59.3, -2.299999999999997]
    ['Rhamondre Stevenson', 25, 25.4, -0.3999999999999986]
    ['Adam Thielen', 130, 129.3, 0.6999999999999886]
    ['Christian McCaffrey', 2, 1.3, 0.7]
    ['Deebo Samuel', 38, 37.0, 1.0]
    ["D'Andre Swift", 50, 48.7, 1.2999999999999972]
    ['Jahan Dotson', 77, 75.7, 1.2999999999999972]
    ['Tee Higgins', 31, 29.0, 2.0]
    ['Michael Thomas', 107, 104.9, 2.0999999999999943]
    ['Tyreek Hill', 15, 12.9, 2.0999999999999996]
    ['Christian Kirk', 71, 68.7, 2.299999999999997]
    ['Allen Lazard', 121, 118.7, 2.299999999999997]
    ['Devin Singletary', 119, 116.1, 2.9000000000000057]
    ['Nick Chubb', 11, 7.8, 3.2]
    ['Austin Ekeler', 6, 2.0, 4.0]
    ['DeVonta Smith', 36, 31.7, 4.300000000000001]
    ['Davante Adams', 22, 16.3, 5.699999999999999]
    ['Jonathan Taylor', 9, 2.7, 6.3]
    ['Derrick Henry', 16, 9.7, 6.300000000000001]
    ['James Conner', 69, 62.4, 6.600000000000001]
    ['Mike Evans', 73, 66.0, 7.0]
    ['Jerry Jeudy', 61, 53.4, 7.600000000000001]
    ['Breece Hall', 24, 15.6, 8.4]
    ['Mark Andrews', 33, 24.5, 8.5]
    ['Tua Tagovailoa', 103, 94.5, 8.5]
    ['Aaron Jones', 42, 33.1, 8.899999999999999]
    ['Saquon Barkley', 13, 3.9, 9.1]
    ['Josh Jacobs', 17, 7.9, 9.1]
    ['Tony Pollard', 21, 11.9, 9.1]
    ['Daniel Jones', 106, 95.6, 10.400000000000006]
    ['Keenan Allen', 58, 47.2, 10.799999999999997]
    ['David Montgomery', 60, 48.9, 11.100000000000001]
    ['Brandin Cooks', 112, 100.7, 11.299999999999997]
    ['James Cook', 96, 84.5, 11.5]
    ['JuJu Smith-Schuster', 117, 105.1, 11.900000000000006]
    ['Elijah Mitchell', 113, 99.6, 13.400000000000006]
    ['Elijah Moore', 128, 114.6, 13.400000000000006]
    ['Calvin Ridley', 48, 34.3, 13.700000000000003]
    ['Najee Harris', 34, 19.0, 15.0]
    ['Kareem Hunt', 139, 123.8, 15.200000000000003]
    ['Travis Etienne', 28, 12.3, 15.7]
    ['J.K. Dobbins', 46, 29.6, 16.4]
    ['Amari Cooper', 56, 39.5, 16.5]
    ['Russell Wilson', 132, 115.0, 17.0]
    ['Jared Goff', 125, 107.6, 17.400000000000006]
    ['Darren Waller', 80, 62.5, 17.5]
    ['Dak Prescott', 95, 77.0, 18.0]
    ['Rashaad Penny', 98, 78.9, 19.099999999999994]
    ['Kadarius Toney', 108, 88.6, 19.400000000000006]
    ['Dallas Goedert', 79, 58.4, 20.6]
    ['Courtland Sutton', 111, 90.0, 21.0]
    ['Aaron Rodgers', 129, 107.9, 21.099999999999994]
    ['Jakobi Meyers', 123, 101.2, 21.799999999999997]
    ['Damien Harris', 115, 93.1, 21.900000000000006]
    ['Dalvin Cook', 47, 24.7, 22.3]
    ['Jameson Williams', 83, 60.6, 22.4]
    ['Dameon Pierce', 65, 42.4, 22.6]
    ['George Pickens', 99, 75.6, 23.400000000000006]
    ['Jamaal Williams', 100, 75.3, 24.700000000000003]
    ['Cam Akers', 64, 38.6, 25.4]
    ['Christian Watson', 70, 41.8, 28.200000000000003]
    ['Mike Williams', 81, 52.4, 28.6]
    ['Tyler Lockett', 85, 56.0, 29.0]
    ['Darnell Mooney', 140, 110.5, 29.5]
    ['George Kittle', 59, 23.8, 35.2]
    ['Rashod Bateman', 116, 79.9, 36.099999999999994]
    ['T.J. Hockenson', 78, 39.9, 38.1]
    ['Evan Engram', 126, 86.6, 39.400000000000006]
    ['Kirk Cousins', 131, 91.4, 39.599999999999994]
    ['Kyle Pitts', 90, 47.7, 42.3]
    ['Isiah Pacheco', 97, 54.2, 42.8]
    ['David Njoku', 138, 92.3, 45.7]
    ['Tyler Allgeier', 120, 60.1, 59.9]
    

    We can now use pandas , Python's data manipulation library, to format our data as a table for better readability.

    import pandas as pd
    df = pd.DataFrame(sorted_diffs, columns=['name', 'trade_value_rank', 'adp', 'tv - adp'])
    with pd.option_context('display.max_rows', None):
      display(df[:10])
    name trade_value_rank adp tv - adp
    0 Jahmyr Gibbs 30 112.6 -82.6
    1 Jaxon Smith-Njigba 63 136.4 -73.4
    2 Anthony Richardson 76 147.7 -71.7
    3 Devon Achane 92 160.8 -68.8
    4 Zach Charbonnet 82 146.1 -64.1
    5 Zay Flowers 88 150.2 -62.2
    6 Jordan Addison 86 146.9 -60.9
    7 Quentin Johnston 84 144.4 -60.4
    8 Kyler Murray 89 142.2 -53.2
    9 Trevor Lawrence 40 70.3 -30.3
    10 Diontae Johnson 66 94.7 -28.7
    11 Dalton Kincaid 114 140.8 -26.8
    12 Skyy Moore 124 150.6 -26.6
    13 Samaje Perine 94 119.1 -25.1
    14 Jordan Love 136 158.9 -22.9
    15 Jerick McKinnon 102 124.7 -22.7
    16 Justin Herbert 43 65.6 -22.6
    17 Alvin Kamara 49 71.5 -22.5
    18 Lamar Jackson 39 60.0 -21.0
    19 Javonte Williams 52 73.0 -21.0
    20 Deshaun Watson 68 87.5 -19.5
    21 Alexander Mattison 74 93.3 -19.3
    22 Patrick Mahomes 12 30.8 -18.8
    23 Rachaad White 67 85.3 -18.3
    24 Chris Godwin 55 71.2 -16.2
    25 Jalen Hurts 26 41.0 -15.0
    26 Brandon Aiyuk 54 68.0 -14.0
    27 Bijan Robinson 4 17.4 -13.4
    28 Marquise Brown 72 84.9 -12.9
    29 Antonio Gibson 91 103.2 -12.2
    30 Jaylen Warren 133 144.4 -11.4
    31 A.J. Brown 8 19.2 -11.2
    32 Garrett Wilson 18 28.1 -10.1
    33 Joe Burrow 37 47.0 -10.0
    34 Josh Allen 20 29.8 -9.8
    35 Joe Mixon 41 50.4 -9.4
    36 Drake London 53 62.0 -9.0
    37 Cooper Kupp 5 13.8 -8.8
    38 Treylon Burks 75 83.8 -8.8
    39 CeeDee Lamb 10 17.7 -7.7
    40 Miles Sanders 35 41.2 -6.2
    41 Ezekiel Elliott 105 110.6 -5.6
    42 Justin Fields 51 56.2 -5.2
    43 Jaylen Waddle 19 23.8 -4.8
    44 Chris Olave 27 31.6 -4.6
    45 Stefon Diggs 14 18.1 -4.1
    46 Ja'Marr Chase 3 6.4 -3.4
    47 Amon-Ra St. Brown 23 26.3 -3.3
    48 Terry McLaurin 45 47.7 -2.7
    49 Justin Jefferson 1 3.7 -2.7
    50 Travis Kelce 7 9.5 -2.5
    51 DeAndre Hopkins 57 59.3 -2.3
    52 Rhamondre Stevenson 25 25.4 -0.4
    53 Adam Thielen 130 129.3 0.7
    54 Christian McCaffrey 2 1.3 0.7
    55 Deebo Samuel 38 37.0 1.0
    56 D'Andre Swift 50 48.7 1.3
    57 Jahan Dotson 77 75.7 1.3
    58 Tee Higgins 31 29.0 2.0
    59 Michael Thomas 107 104.9 2.1
    60 Tyreek Hill 15 12.9 2.1
    61 Christian Kirk 71 68.7 2.3
    62 Allen Lazard 121 118.7 2.3
    63 Devin Singletary 119 116.1 2.9
    64 Nick Chubb 11 7.8 3.2
    65 Austin Ekeler 6 2.0 4.0
    66 DeVonta Smith 36 31.7 4.3
    67 Davante Adams 22 16.3 5.7
    68 Jonathan Taylor 9 2.7 6.3
    69 Derrick Henry 16 9.7 6.3
    70 James Conner 69 62.4 6.6
    71 Mike Evans 73 66.0 7.0
    72 Jerry Jeudy 61 53.4 7.6
    73 Breece Hall 24 15.6 8.4
    74 Mark Andrews 33 24.5 8.5
    75 Tua Tagovailoa 103 94.5 8.5
    76 Aaron Jones 42 33.1 8.9
    77 Saquon Barkley 13 3.9 9.1
    78 Josh Jacobs 17 7.9 9.1
    79 Tony Pollard 21 11.9 9.1
    80 Daniel Jones 106 95.6 10.4
    81 Keenan Allen 58 47.2 10.8
    82 David Montgomery 60 48.9 11.1
    83 Brandin Cooks 112 100.7 11.3
    84 James Cook 96 84.5 11.5
    85 JuJu Smith-Schuster 117 105.1 11.9
    86 Elijah Mitchell 113 99.6 13.4
    87 Elijah Moore 128 114.6 13.4
    88 Calvin Ridley 48 34.3 13.7
    89 Najee Harris 34 19.0 15.0
    90 Kareem Hunt 139 123.8 15.2
    91 Travis Etienne 28 12.3 15.7
    92 J.K. Dobbins 46 29.6 16.4
    93 Amari Cooper 56 39.5 16.5
    94 Russell Wilson 132 115.0 17.0
    95 Jared Goff 125 107.6 17.4
    96 Darren Waller 80 62.5 17.5
    97 Dak Prescott 95 77.0 18.0
    98 Rashaad Penny 98 78.9 19.1
    99 Kadarius Toney 108 88.6 19.4
    100 Dallas Goedert 79 58.4 20.6
    101 Courtland Sutton 111 90.0 21.0
    102 Aaron Rodgers 129 107.9 21.1
    103 Jakobi Meyers 123 101.2 21.8
    104 Damien Harris 115 93.1 21.9
    105 Dalvin Cook 47 24.7 22.3
    106 Jameson Williams 83 60.6 22.4
    107 Dameon Pierce 65 42.4 22.6
    108 George Pickens 99 75.6 23.4
    109 Jamaal Williams 100 75.3 24.7
    110 Cam Akers 64 38.6 25.4
    111 Christian Watson 70 41.8 28.2
    112 Mike Williams 81 52.4 28.6
    113 Tyler Lockett 85 56.0 29.0
    114 Darnell Mooney 140 110.5 29.5
    115 George Kittle 59 23.8 35.2
    116 Rashod Bateman 116 79.9 36.1
    117 T.J. Hockenson 78 39.9 38.1
    118 Evan Engram 126 86.6 39.4
    119 Kirk Cousins 131 91.4 39.6
    120 Kyle Pitts 90 47.7 42.3
    121 Isiah Pacheco 97 54.2 42.8
    122 David Njoku 138 92.3 45.7
    123 Tyler Allgeier 120 60.1 59.9

    Challenge yourself

  • The trade_value and adp diffs include a lot of decimals. Can you print this in a prettier format? Example: 8.2000000003 -> 8
  • Can you figure out how to include players whose name's don't exactly match between the two sources? Example: DK Metcalf
  • Concluding thoughts

    Fetching, reformatting, and comparing multiple data sources is a very common programming task. I'm excited I got the opportunity to teach these concepts with an example using fantasy football data. I've spent thousands of hours learning Python, web development, infrastructure, and more on my own fantasy football projects, and have got plenty of help from the fantasy community, so I'm happy to take this opportunity to collaborate to pay it forward.