What is PigPro?¶
PigPro is a 0โ10 composite score that ranks every fantasy-relevant NFL player using a weighted blend of eight independent signals. It replaces a scattering of per-source rankings (Yahoo's default projection, Sleeper's search_rank, FFC ADP, our own ML regressor, Firecrawl news sentiment) with one number โ and a transparent breakdown so you can see exactly why a player got that number.
Every page in the app that shows a player (/draft-analytics, /lineup, /waivers, /offseason-intel, /players, /draft-room) opens the same PigPro trading card when you click. One source of truth, one UI.
Currently shipping: v1.1 Hybrid. Promoted in April 2026 after a backtest cycle where v1's seven-component formula was extended with a Usage component (top-N precision improved at every skill position; rank correlation +0.019). See the formula page for the exact weights and ml-backtest for the head-to-head numbers.
The eight components¶
flowchart LR
A[ML Projection
27.6%] --> SCORE
B[ADP Value
23%] --> SCORE
C[VOR
18.4%] --> SCORE
D[Consistency
9.2%] --> SCORE
E[Boom Potential
9.2%] --> SCORE
H[Usage / Opportunity
8%] --> SCORE
F[Situation
2.3%] --> SCORE
G[News Impact
2.3%] --> SCORE
SCORE[PigPro 0โ10]
Each component is itself a 0โ10 score, multiplied by its weight and summed. A position multiplier (~0.9โ1.35) tilts the final raw sum into positional reality โ RBs and QBs can't earn the same "value" by the same yardage.
1. ML Projection (27.6%)¶
Our in-house draft-value regressor (GradientBoostingRegressor per position, trained on 2022 + 2023 NFL seasons + rookie features) predicts the upcoming season's total PPR points. That prediction is converted to a 0โ10 score using per-position maxes (QB 24 PPG, RB 22, WR 22, TE 16).
Source: ml_draft_predictions table, populated nightly by the ml-draft-retrain CronJob.
QB special case: for QB-position players, the Usage weight (8%) is folded into ML Projection, making QB ML weight 35.6%. This is because the Usage formula (snap-share + rushing-share) under-weighted pocket passers in early testing. See the formula page for details.
2. ADP Value (23%)¶
The "market price." ADP 1 โ 10.0, ADP 200+ โ 1.0. Linear scale. Pulled from Sleeper search_rank with FFC ADP overriding when available. Both sources now persist nightly to adp_records (April 2026), so we have movement history per player. Yahoo ADP is also collected daily into adp_records (source='yahoo', one global pool) and powers the Yahoo ADP arbitrage overlay โ the edge badges on the Value Map and Draft War Room.
A player with a strong ML projection but high ADP is a value target; a player with a weak projection but low ADP is a fade regardless of name recognition.
3. Value Over Replacement (18.4%)¶
max(0, replacement_ADP โ player_ADP) / (replacement / 10). Replacement ADP is position-specific (e.g., RB replacement is around ADP 150, QB around 120). Captures positional scarcity: a mid-tier RB is worth more than a mid-tier QB because the QB floor is deeper.
Formula + thresholds: league_format.py.
4. Consistency (9.2%)¶
Coefficient of variation on last season's weekly PPR:
CoV = stdev(weekly_ppr) / mean(weekly_ppr)
consistency_score = 10 ร (1 โ min(CoV / 1.5, 1.0))
Lower weekly variance โ higher score. A player averaging 18 PPG with a 4-PPG standard deviation scores higher than one averaging 18 PPG with a 12-PPG standard deviation.
Needs at least 8 games of data in the prior season; otherwise defaults to 5.0.
5. Boom Potential (9.2%)¶
Upside, measured as the ratio of top-quartile weeks to median:
boom_ratio = percentile_90(weekly_ppr) / median(weekly_ppr)
boom_score = min(10, (boom_ratio โ 1) ร 5)
A player whose 90th-percentile week is 2ร their median week scores 5/10. A 3ร boomer scores 10/10. Same 8-game minimum as consistency.
6. Usage / Opportunity (8%) โ new in v1.1¶
How much of his team's offensive work does this player get? The single biggest blind spot in v1, where ascending TEs (Bowers, McBride) and high-snap WRs (ARSB) were under-valued because none of the seven prior components captured raw opportunity.
Composite per position:
- WR/TE:
target_share ร 0.55 + snap_pct ร 0.45 - RB:
rush_share ร 0.45 + target_share ร 0.25 + snap_pct ร 0.30 - QB:
snap_pct ร 0.70 + rush_share ร 0.30(zeroed in final composite โ see ML Projection note above)
The composite is then percentile-ranked within position to produce the 0โ10 score. So a WR with 25% target share + 90% snap share lands above one with 18% + 80%.
Sources: nflverse_weekly_stats.target_share (precomputed), nflverse_snap_counts.offense_pct, and rush_share derived in SQL as carries / team_total_carries.
Rookie fallback: players with <12 career NFL games AND drafted in the last 2 seasons substitute a draft-capital proxy: clamp(10 โ draft_ovr/27, 1, 10). Pick 1 โ 9.96, Pick 32 โ 8.8, UDFA โ 2. Tagged in the components JSONB as source: rookie_proxy so the trading card can display a "~" indicator.
7. Situation (2.3%)¶
Offseason movement signal โ coaching changes, team switches, depth-chart shuffles. Pulled from situation_scores (populated daily by the situation-tracking CronJob from Firecrawl-scraped offseason intel).
Only ~260 players carry a non-zero situation score at any given time (the ones actually mentioned in recent news). Contribution is small by design โ it nudges, doesn't rule.
8. News Impact (2.3%)¶
Recent player news, extracted structured-ly by Claude Haiku from nightly Firecrawl scrapes of ESPN/RotoWire/NFL.com/FantasyPros. For each mentioned player, Claude emits {direction: positive|negative|neutral, magnitude: 0-1, confidence: 0-1} and we aggregate the last 7 days weighted by recency:
news_score = 5.0 + clamp(weighted_impact ร 2.5, -5, 5)
5.0 = neutral (no recent news). Max +5 or โ5 based on news flow.
Tiers โ USDA-Grade Labels¶
Single-word labels using the USDA-grade quality vocabulary. Universal scale (every fantasy player has seen these on a steak menu), fits the pigskin/agricultural brand without being cute, and every label is positively framed:
| Tier | Score | Label | Meaning |
|---|---|---|---|
| 1 | โฅ 7.5 | PRIME | Top quality โ first 2-3 rounds, must-have when available |
| 2 | 5.5 โ 7.5 | CHOICE | Reliable starter โ draft inside ADP range |
| 3 | 3.5 โ 5.5 | SELECT | Lean depth โ K, DEF, RB3/4, late WR; draftable, not avoid |
| 4 | < 3.5 | RESERVE | Waiver pool / final-round flier |
The tier label is also the recommendation field on the trading card and /players table โ no separate action verb. Same string in both columns of pigpro_score_history so downstream consumers reading either field see the same value.
Aligned across pigpro/scorer.py, ml_pipeline/pigpro_v1_5.py, pigpro_v1_1_hybrid.py, and projection_writer.py.
Threshold history: T1 cutoff was 8.0 (now 7.5 so legitimate elites stop landing in T2), T3 cutoff was 4.0 / 3.0 in different scorers (now uniformly 3.5). Earlier label sets included TARGET / CONSIDER / AVOID / SLEEPER and GRAND CHAMPION / BLUE RIBBON / STOCKYARD / STRAY โ both retired in favor of the clean USDA terms.
Rookie cards โ three implicit transitions¶
Brand-new rookies (drafted within the last ~2 seasons, fewer than 12 NFL games) get proxy values for the four components that depend on NFL history: Usage, Boom Potential, Consistency, Durability. The proxies are derived from draft capital โ Pick 1 โ Usage 9.96, Pick 32 โ 8.8, UDFA โ 2.0. Components flagged with source: 'rookie_proxy' show a gold ~ PROXY pip on the trading card.
The transitions are automatic โ three triggers baked into ml_pipeline/pigpro_v1_5.py:
| Trigger | When | What changes |
|---|---|---|
| Day 0โ2 post-draft | nflverse-backfill + Sleeper updates ingest | NFL Draft slot, combine measurements, college, age, height/weight populate. Score remains proxy-driven. |
| Career games โฅ 12 | Mid rookie season (typically Week 12 of the rookie year) | Usage / Boom / Consistency / Durability switch from proxies to measured signal. Gold ~ PROXY pip disappears. |
| draft_year < season โ 2 | Two calendar years post-draft | Forced exit from the rookie regime even if the player was injured all year. Components fall back to v1 defaults if no measured signal exists. |
The trading card itself shows a banner โ ๐ฃ ROOKIE CARD โ Usage / Boom / Durability inferred from draft capital. Real signal arrives once the player accumulates 12 NFL games (~Week 12 of the season). โ whenever years_exp == 0 so users know what's measured vs. inferred.
Defense / Special-Teams cards¶
Team defenses don't fit the player composite โ no target_share, no ml_projection, no situation. They get a simplified 0.70 ร ADP value + 0.30 ร prior PPR rank scoring path (see ValueScorer.score_kicker_defense). Currently the prior-PPR-rank component defaults to 5.0 because nflverse import_weekly_data() ships zero team-defense aggregation; the math collapses to ADP-driven.
Cards for DEFs render with:
- Sleeper team logo (via sleepercdn.com/images/team_logos/nfl/{abbr}.png) instead of a player headshot
- "TEAM DEFENSE" label in the meta row (no age/height/weight)
- Banner: ๐ก๏ธ TEAM DEFENSE โ scored on a 70% ADP / 30% prior-rank composite. Player-level components don't apply.
- Six of the eight skill-position components show 0.0 (genuinely don't apply); only adp_value and prior_ppr_rank are populated
When we wire up a real DEF season-rank source (FantasyPros team-defense rankings or nflverse_pbp aggregation), the second component activates and DEF differentiation tightens. Until then, ADP is the only signal.
Not a projection โ a value ranking¶
PigPro is a ranking signal, not a projection. The Projected / Ceiling / Floor numbers on the card come from the ML Projection component and are in PPR points; the 0โ10 score itself is a percentile-like value number. A player projected for 180 PPR with a great context can score higher than a player projected for 220 with red flags.
When you want the raw points prediction, read the Projected tile on the trading card. When you want "should I draft this person," read the PigPro score.