<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lucas</title>
    <description>The latest articles on DEV Community by Lucas (@lukeinthatfluke).</description>
    <link>https://dev.to/lukeinthatfluke</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4154603%2Fa3855127-4fc0-4f80-8fa1-e23ccfe178d8.png</url>
      <title>DEV Community: Lucas</title>
      <link>https://dev.to/lukeinthatfluke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lukeinthatfluke"/>
    <language>en</language>
    <item>
      <title>StressFreeFantasy: Lineup Optimization with TabPFN and Real NFL Data</title>
      <dc:creator>Lucas</dc:creator>
      <pubDate>Sun, 04 Oct 2026 01:07:11 +0000</pubDate>
      <link>https://dev.to/lukeinthatfluke/stressfreefantasy-lineup-optimization-with-tabpfn-and-real-nfl-data-2c4d</link>
      <guid>https://dev.to/lukeinthatfluke/stressfreefantasy-lineup-optimization-with-tabpfn-and-real-nfl-data-2c4d</guid>
      <description>&lt;p&gt;&lt;em&gt;This project is a submission for the Hacktoberfest: Build for a Friend DEV Challenge, targeting the **Best Use of TabPFN&lt;/em&gt;* category.*&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Context &amp;amp; Motivation
&lt;/h2&gt;

&lt;p&gt;Me and my brother play in the same competitive fantasy football league, which means my default setting on Sundays is actively rooting for his team to implode. &lt;/p&gt;

&lt;p&gt;That said, watching him agonize every single week over two flex players projected within 0.3 points of each other got painful to witness. &lt;/p&gt;

&lt;p&gt;Default platform projections have known limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static estimates:&lt;/strong&gt; They rarely adjust quickly for game scripts (Vegas totals and spreads).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Positional matchups:&lt;/strong&gt; Opponent defensive strength against specific positions is often averaged out or ignored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Point estimates only:&lt;/strong&gt; They show a single expected number rather than a distribution. In reality, whether you need a high floor (P10) to protect a lead or a high ceiling (P90) to chase upside completely changes who you should start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built &lt;strong&gt;StressFreeFantasy&lt;/strong&gt; to automate these decisions. It syncs with private ESPN leagues, conditions an in-context tabular foundation model on historical NFL data, and outputs an optimized lineup with floor/ceiling estimates. (Though whether I let him use it against me when we play head-to-head remains an open question.)&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Why TabPFN?
&lt;/h2&gt;

&lt;p&gt;Standard tabular models (like XGBoost or LightGBM) require training pipelines, feature scaling, and hyperparameter tuning. More importantly, when leagues use non-standard scoring rules (Full PPR, Half PPR, TE premium, big-play bonuses), a traditional model has to be retrained from scratch for those specific point values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TabPFN&lt;/strong&gt; handles this differently:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;In-Context Adaptation:&lt;/strong&gt; As a prior-data fitted foundation model, it runs in-context learning in a single forward pass. By feeding it 2,000 historical NFL player-weeks recalculated to the user's specific scoring settings, TabPFN adapts instantly without gradient steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantile Outputs:&lt;/strong&gt; TabPFN natively supports querying specific quantiles (&lt;code&gt;quantiles=[0.1, 0.9]&lt;/code&gt;), providing calibrated P10 (floor) and P90 (ceiling) values rather than just a noisy mean.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why Open Innovation Matters Here
&lt;/h3&gt;

&lt;p&gt;Relying on an open-weight, locally runnable tabular foundation model makes all the difference compared to closed cloud APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero API Cost &amp;amp; Unlimited Inference:&lt;/strong&gt; Simulating thousands of matchup permutations and testing historical holdouts incurs zero per-token API charges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Privacy:&lt;/strong&gt; League authentication tokens (&lt;code&gt;espn_s2&lt;/code&gt;, &lt;code&gt;SWID&lt;/code&gt;) and private league rosters stay completely local on the user's machine—never routed through a third-party server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline-Ready In-Context Learning:&lt;/strong&gt; TabPFN runs locally on a consumer laptop CPU/GPU without depending on external proprietary server uptimes right before Sunday kickoffs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Architecture &amp;amp; Data Pipeline
&lt;/h2&gt;

&lt;p&gt;The project is built with Streamlit and ties together three data sources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌────────────────────────────┐
                    │    nflverse / nflreadpy    │
                    │  5 Seasons Historical Data │
                    └─────────────┬──────────────┘
                                  │
                                  ▼
┌──────────────────────┐   ┌──────────────┐   ┌──────────────────────┐
│  Private ESPN League │──▶│   TabPFN     │──▶│ Streamlit Dashboard  │
│  (espn-api / S2&amp;amp;SWID)│   │ In-Context   │   │ Lineup + Floor/Ceil  │
└──────────────────────┘   │ Regressor    │   └──────────────────────┘
                           └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Feature Engineering
&lt;/h3&gt;

&lt;p&gt;Features are computed without data leakage, using strictly pre-game rolling historical signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Player baseline:&lt;/strong&gt; 16-game rolling average (&lt;code&gt;Avg_Pts&lt;/code&gt;), previous week's score (&lt;code&gt;Last_Week_Pts&lt;/code&gt;), and short-term form (&lt;code&gt;Form_L3&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume:&lt;/strong&gt; Rolling 3-game touches and targets (&lt;code&gt;Volume_Proj&lt;/code&gt;), which is historically more stable than point totals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game environment:&lt;/strong&gt; Opponent defensive ranking against the player's specific position (&lt;code&gt;Opp_Def_Rank&lt;/code&gt;), dome status, and Vegas implied team total derived from over/under and point spread:
$$\text{Implied Team Total} = \frac{\text{Vegas Total} + \text{Spread}}{2}$$&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Benchmark &amp;amp; Validation
&lt;/h2&gt;

&lt;p&gt;Fantasy projections have high variance due to random touchdown variance, making raw MAE an incomplete metric. What matters for a manager is whether the model ranks the right player higher in a head-to-head Start/Sit call.&lt;/p&gt;

&lt;p&gt;We set up an out-of-time temporal test, fitting on earlier seasons and testing on an unseen holdout season ($N = 600$ test player-weeks):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Baseline (Avg)&lt;/th&gt;
&lt;th&gt;Baseline (Form)&lt;/th&gt;
&lt;th&gt;TabPFN (Ours)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;MAE&lt;/strong&gt; &lt;em&gt;(lower is better)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;6.84 pts&lt;/td&gt;
&lt;td&gt;7.12 pts&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.91 pts&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Correlation ($r$)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.44&lt;/td&gt;
&lt;td&gt;0.38&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.58&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pairwise Start/Sit Accuracy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;52.8%&lt;/td&gt;
&lt;td&gt;51.4%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;63.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In pairwise head-to-head matchups between players at the same position, TabPFN selected the higher-scoring option &lt;strong&gt;63.7%&lt;/strong&gt; of the time.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Interface &amp;amp; Usage
&lt;/h2&gt;

&lt;p&gt;The Streamlit UI provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ESPN Sync:&lt;/strong&gt; Imports rosters, schedules, and custom scoring tables using league credentials (&lt;code&gt;espn_s2&lt;/code&gt;, &lt;code&gt;SWID&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual Adjustments:&lt;/strong&gt; An interactive data editor to tweak expected volume, health status, or weather/stadium conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lineup Optimizer:&lt;/strong&gt; Greedily fills position slots (QB, RB, WR, TE, FLEX) sorted by projected output and matchup edge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj0vk6v85lq64x1oauj4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj0vk6v85lq64x1oauj4r.png" alt="StressFreeFantasy Streamlit App" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Testing &amp;amp; Feedback
&lt;/h2&gt;

&lt;p&gt;Since we play in the same league, I initially tested the engine on my own roster to see how the recommendations differed from ESPN's defaults. Rather than relying on a single static projection, having direct access to calibrated P10 (floor) and P90 (ceiling) intervals made marginal Start/Sit calls immediately clearer.&lt;/p&gt;

&lt;p&gt;After seeing the floor/ceiling spreads and the pairwise accuracy numbers, I showed the tool to my brother to help him with his own weekly lineup headaches. He now uses it as a sanity check before kickoff rather than overthinking marginal calls—which unfortunately means his roster is noticeably harder to beat when we play each other.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Repository &amp;amp; AI Transparency
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/lucasantonsson/StressFreeFantasy" rel="noopener noreferrer"&gt;lucasantonsson/StressFreeFantasy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; Python, Streamlit, TabPFN, &lt;code&gt;nflreadpy&lt;/code&gt;, &lt;code&gt;espn-api&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Collaboration:&lt;/strong&gt; Code generation, pipeline scaffolding, and debugging were assisted by Claude and Gemini, while system design, logic requirements, and validation were directed independently.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>tabpfn</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
