cwendt94 / espn-api

ESPN Fantasy API! (Football, Basketball)
MIT License
628 stars 199 forks source link

Week 2 Projected Points Appear to be a Total - Football #571

Closed russellkt closed 1 month ago

russellkt commented 1 month ago

Running through my notebooks for the waiver wire I am getting what appears to be Total Projected Points rather than Week 2 Projections. It is occurring for both Free Agents Projected points and for the Stats of a Rostered Player. Example for Garrett Wilson(on Roster) showing Week 2 Projections of 266.48:


{0: {'points': 12.0,
  'breakdown': {'receivingReceptions': 6.0,
   'receivingYards': 60.0,
   '47': 12.0,
   '48': 6.0,
   '49': 3.0,
   '50': 2.0,
   '51': 1.0,
   '54': 1.0,
   'receivingTargets': 11.0,
   'receivingYardsAfterCatch': 27.0,
   'receivingYardsPerReception': 10.0,
   'teamLoss': 1.0,
   '210': 1.0,
   '213': 3.0},
  'avg_points': 12.0,
  'projected_points': 251.59,
  'projected_breakdown': {'rushingAttempts': 4.390871446,
   'rushingYards': 1.565316499,
   'rushingTouchdowns': 0.198176164,
   'rushing2PtConversions': 0.010924088,
   '27': 4.0,
   '28': 2.0,
   '29': 1.0,
   'rushing40PlusYardTD': 0.008071739,
   'rushing50PlusYardTD': 0.005650218,
   'rushing100To199YardGame': 0.001280221,
   'rushing200PlusYardGame': 4.3689e-05,
   'rushingYardsPerAttempt': 5.389340738,
   'receivingYards': 75.40822275,
   'receivingTouchdowns': 9.074646404,
   'receiving2PtConversions': 0.454513676,
   'receiving40PlusYardTD': 0.223645547,
   'receiving50PlusYardTD': 0.146152365,
   '47': 227.0,
   '48': 113.0,
   '49': 56.0,
   '50': 45.0,
   '51': 22.0,
   'receivingReceptions': 80.50048626,
   'receiving100To199YardGame': 3.480679281,
   'receiving200PlusYardGame': 0.107649875,
   'receivingTargets': 136.4903748,
   'receivingYardsPerReception': 14.16134175,
   '2PtConversions': 0.465437763,
   'fumbleRecoveredForTD': 0.007470439,
   '66': 0.087817429,
   '67': 1.610009725,
   'fumbles': 1.697827154,
   '70': 0.040396017,
   '71': 0.901605446,
   'lostFumbles': 0.942001463,
   'turnovers': 0.942001463,
   '210': 15.11764706,
   '212': 3.285509124,
   '213': 52.34635775},
  'projected_avg_points': 16.77},
 **2: {'projected_points': 266.48**,
  'projected_breakdown': {'rushingAttempts': 4.305681985,
   'rushingYards': 1.511204829,
   'rushingTouchdowns': 0.182071948,
   'rushing2PtConversions': 0.010003328,
   '27': 4.0,
   '28': 2.0,
   '29': 1.0,
   'rushing40PlusYardTD': 0.007915901,
   'rushing50PlusYardTD': 0.005541131,
   'rushing100To199YardGame': 0.001431239,
   'rushing200PlusYardGame': 4.88e-05,
   'rushingYardsPerAttempt': 5.615667239,
   'receivingYards': 76.31669361,
   'receivingTouchdowns': 9.193852151,
   'receiving2PtConversions': 0.458929306,
   'receiving40PlusYardTD': 0.208249784,
   'receiving50PlusYardTD': 0.136091234,
   '47': 244.0,
   '48': 122.0,
   '49': 61.0,
   '50': 48.0,
   '51': 24.0,
   'receivingReceptions': 86.73210766,
   'receiving100To199YardGame': 4.365454929,
   'receiving200PlusYardGame': 0.13501407,
   'receivingTargets': 146.3482622,
   'receivingYardsPerReception': 14.07860515,
   '2PtConversions': 0.468932634,
   'fumbleRecoveredForTD': 0.008011325,
   '66': 0.08611364,
   '67': 1.734642153,
   'fumbles': 1.820755793,
   '70': 0.039612274,
   '71': 0.971399606,
   'lostFumbles': 1.01101188,
   'turnovers': 1.01101188,
   '210': 16.0,
   '212': 3.163847919,
   '213': 56.11877819},
  'projected_avg_points': 16.65},
 1: {'projected_points': 16.54,
  'projected_breakdown': {'rushingAttempts': 0.224516457,
   'rushingYards': 1.142492027,
   'rushingTouchdowns': 0.009255704,
   'rushing2PtConversions': 0.000516313,
   'rushing40PlusYardTD': 0.000412597,
   'rushing50PlusYardTD': 0.000288818,
   'rushing100To199YardGame': 4.88e-05,
   'rushing200PlusYardGame': 1.67e-06,
   'rushingYardsPerAttempt': 5.088678316,
   'receivingYards': 79.25650393,
   'receivingTouchdowns': 0.48340866,
   'receiving2PtConversions': 0.024499994,
   'receiving40PlusYardTD': 0.012207643,
   'receiving50PlusYardTD': 0.007977695,
   '47': 15.0,
   '48': 7.0,
   '49': 3.0,
   '50': 3.0,
   '51': 1.0,
   'receivingReceptions': 5.616434658,
   'receiving100To199YardGame': 0.294959167,
   'receiving200PlusYardGame': 0.00912,
   'receivingTargets': 9.641873483,
   'receivingYardsPerReception': 14.11153316,
   '2PtConversions': 0.025016307,
   'fumbleRecoveredForTD': 0.000514,
   '66': 0.004490329,
   '67': 0.112328693,
   'fumbles': 0.116819022,
   '70': 0.002065551,
   '71': 0.062904068,
   'lostFumbles': 0.06496962,
   'turnovers': 0.06496962,
   '210': 1.0,
   '212': 0.180998594,
   '213': 3.595797523},
  'projected_avg_points': 0,
  'points': 12.0,
  'breakdown': {'receivingReceptions': 6.0,
   'receivingYards': 60.0,
   '47': 12.0,
   '48': 6.0,
   '49': 3.0,
   '50': 2.0,
   '51': 1.0,
   '54': 1.0,
   'receivingTargets': 11.0,
   'receivingYardsAfterCatch': 27.0,
   'receivingYardsPerReception': 10.0,
   'teamLoss': 1.0,
   '210': 1.0,
   '213': 3.0},
  'avg_points': 0}}```
DesiPilla commented 1 month ago

If we assign this dictionary to a variable called data, you'll see that there are two keys.

>>> data.keys()
[0, 1]

In data[1] are all the week specific stats & projections for a player. For example, to get the projected point total for just the single week:

>>> data[1]['projected_points']
16.54
russellkt commented 1 month ago

Thanks @DesiPilla . I am pulling the data[2]['projected_points'] but the value is 266.48 for Garrett Wilson with similar values for all of the players both on roster and free agents. The code worked fine all last season and also appears reasonable for Week 1 or data[1].

2: {'projected_points': 266.48,

First Five Free Agents:

[Player(Ka'imi Fairbairn, points:0, projected:131.89), Player(Devin Singletary, points:0, projected:193.02), Player(Cameron Dicker, points:0, projected:129.94), Player(Chiefs D/ST, points:0, projected:96.36), Player(Zach Charbonnet, points:0, projected:121.6)]

DesiPilla commented 1 month ago

Can you share the code you used to pull the data?

russellkt commented 1 month ago

Sure, I have this in a jupyter notebook so here is the relevant code:

wk=2

fhope = League(league_id=***, year=2024, swid='{***}', espn_s2=espn_auth)

free_agents = fhope.free_agents(size=250)

fas_df = pd.DataFrame([o.__dict__ for o in free_agents])

rustlers = fhope.teams[8]

roster = rustlers.roster

rustlers_df = pd.DataFrame([o.__dict__ for o in rustlers.roster])

rustlers_df["projected_points"] = rustlers_df.apply(
         lambda row: row["stats"][wk]["projected_points"],
         axis=1)

rustlers_fa = pd.concat([fas_df, rustlers_df], ignore_index=True)

rustlers_fa[['name','projected_points']]

Output:

image

DesiPilla commented 1 month ago

Interesting. After looking into it, I think it might be a glitch on ESPN's part. The projected_avg_points for Bijan is 19.7 pts, which is what the ESPN website/app says is his Week 2 projection. I think their API is probably glitching out and will hopefully get fixed soon.

>>> player["stats"][2]["projected_points"]
313.3
>>> player["stats"][2]["projected_avg_points"]
19.7
russellkt commented 1 month ago

Thank you, the projected_avg_points does not match up exactly with the projected points I am seeing on the website but will continue to monitor and report back.

billwert commented 1 month ago

@DesiPilla Thanks for digging this out! Was exactly the fix I was looking for, hadn't noticed the avg field seemed correct.

josh-spratt commented 1 month ago

Also experiencing this issue!

billwert commented 1 month ago

I realized later it isn’t always right - Josh Jacob’s projected avg doesn’t match the roster on the site. Haven’t gotten to debug it to trace further tho..

Thanks, -Bill


From: Josh Spratt @.> Sent: Wednesday, September 11, 2024 5:56:54 PM To: cwendt94/espn-api @.> Cc: Comment @.***> Subject: Re: [cwendt94/espn-api] Week 2 Projected Points Appear to be a Total (Issue #571)

Also experiencing this issue!

— Reply to this email directly, view it on GitHubhttps://github.com/cwendt94/espn-api/issues/571#issuecomment-2345046830 or unsubscribehttps://github.com/notifications/unsubscribe-auth/ABCQI4BVUMZBKLJPO3PVPETZWDRFNBFKMF2HI4TJMJ2XIZLTSOBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDUOJ2WLJDOMFWWLLTXMF2GG2C7MFRXI2LWNF2HTAVFOZQWY5LFUVUXG43VMWSG4YLNMWVXI2DSMVQWIX3UPFYGLLDTOVRGUZLDORPXI6LQMWWES43TOVSUG33NNVSW45FGORXXA2LDOOJIFJDUPFYGLKTSMVYG643JORXXE6NFOZQWY5LFVEYTSOBWGY4TIOBVQKSHI6LQMWSWS43TOVS2K5TBNR2WLKRSGUYTOMJUHE2DGMFHORZGSZ3HMVZKMY3SMVQXIZI. You are receiving this email because you commented on the thread.

Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

bwright2810 commented 1 month ago

I am seeing the same issue.

russellkt commented 1 month ago

Taking a quick look on the website it appears the correct value is stats[{"appliedTotal":xxx, ..."scoringPeriodId":2}] I'm not as optimistic that espn will be fixing as their site appears to be working fine. Hopefully I'll have more time to dive in and debug soon.

bwright2810 commented 1 month ago

Right, what I ended up doing to cover for this in the meantime is to parse the response of:

https://lm-api-reads.fantasy.espn.com/apis/v3/games/ffl/seasons/2024/segments/0/leagues/{league_id}?rosterForTeamId=1&view=mDraftDetail&view=mLiveScoring&view=mMatchupScore&view=mPendingTransactions&view=mPositionalRatings&view=mRoster&view=mSettings&view=mTeam&view=modular&view=mNav

which is the API called on the ESPN matchup page. That "appliedTotal" field you mentioned has the projected points for the week. Thanks for taking a look.

russellkt commented 1 month ago

It appears there are actually two values in the json for scoringPeriodId: 2, one appliedTotal appears to be ROS, and one for the week. Looking closer it looks like the correct one for the week is delineated by "statSplitTypeId": 1 and the ROS by "statSplitTypeId": 2

russellkt commented 1 month ago

I wish my python skills were better but I did fork the code and it appears there is no delineation for statSplitTypeId in the Player class when parsing the stats. My thinking is espn changed the api to be able to track the rest of the season stats from original as the season progresses. In line 42 it does delineate between stat source which I believe is the delineation between actual and projected.

russellkt commented 1 month ago

Was able to fork and get a codespace up and running. When debugging, it appears the stats for scoring period 2 are getting set correctly but then overriden by the second stats for scoring period 2 of statSplitTypeId: 2 which appears to have the rest of the season projections.

russellkt commented 1 month ago

I was able to correct the behavior by changing line 34 of the Player class file from

if stats.get('seasonId') != year:

to

if stats.get('seasonId') != year or stats.get('statSplitTypeId') == 2:

However, I have not issued a pull request since my skills are weak and there might be a better way to accomplish.

cwendt94 commented 1 month ago

Thanks for this update and investigation! I believe I saw something similar in baseball and had to do the same https://github.com/cwendt94/espn-api/commit/80bcefc2bd96178b93d6503ecf2223b863d93d57.

I will create a fix!

cwendt94 commented 1 month ago

should be fixed in v0.38.1