Football Transfer Valuation Model
A market-segmented valuation engine built on 300,000+ historical player valuations — not one model pricing every player the same way, but a specialized pricing logic per market tier, with SHAP explainability behind every number.
Overpaying in the transfer market can derail a club's finances, and too many valuation calls still lean on reputation over data. But the deeper problem with a naive approach is subtler: training one regression model across every player type forces it to average away the very differences that actually explain price — a bench player and a global superstar don't follow the same pricing logic, so a single model can't price either one well.
From a raw Kaggle dump to a segmented pricing engine
Building the data foundation in SQL
Ingested the full Transfermarkt dataset — players, valuations, clubs, transfers, appearances, game events, lineups — into PostgreSQL and modeled it into a set of standardized views, culminating in a master view joining performance (goals, assists, minutes, captaincy) with financial history across 300,000+ player-season records.
Deciding what history actually matters
The obvious move was to use the full 2008–2026 window, but earlier years were shaped by forces that have nothing to do with a player's performance: Brazil's Lei Pelé and Europe's Bosman ruling reshaped transfer economics, the 2017 Neymar-to-PSG transfer (€222M) reset what an "elite" fee looks like, and the 2019–2021 pandemic triggered a price boom followed by a sharp crash. Rather than ask a model to learn through all of that noise, the dataset was narrowed to 2021 onward.
Turning a snapshot into a timeline
The raw data treated each valuation as an isolated fact. Rebuilding it around age_at_valuation — a player's exact age at the moment of each specific valuation, not just their current age — turned it into a proper panel: a player like Vinícius Júnior or Erling Haaland shows up multiple times, once per valuation snapshot, tracking how their price moved as their career did. Filtering out under-18s also removed thousands of youth-academy rows with no real market value.
Cutting geopolitical noise
The Russian league lost real market relevance after the war in Ukraine, so it was excluded rather than left in as stale signal. The dataset was also narrowed to the leagues that actually move the market: Europe's "Big Five" plus high-liquidity leagues like Portugal, Belgium, the Netherlands, Brazil, Mexico, MLS and Saudi Arabia.
Segmenting the market instead of flattening it
K-Means clustering, tuned with the elbow method, split players into distinct market tiers by performance and league weight — so each tier could get its own specialized pricing logic instead of one compromise model trying to fit everyone.
Letting four models compete per tier
XGBoost, Random Forest, Ridge Regression and k-NN were each trained and evaluated per cluster. The most interesting result wasn't which algorithm "won" overall — Ridge, the simplest of the four, matched or beat the tree-based models in most tiers. Once the market segmentation was doing the heavy lifting, adding model complexity didn't buy much more.
Refining the clusters themselves
The largest tier — the "mass market," roughly 80% of all players — stayed stubbornly hard to predict even after tuning. Isolation Forest separated a genuinely noisy sub-segment from the predictable majority, and two smaller, similar tiers were merged for more stable training data. GridSearchCV then tuned each tier's hyperparameters individually rather than applying one global configuration everywhere.
Making the model explainable
SHAP (Shapley Additive exPlanations) breaks down individual predictions into an itemized, euro-denominated "receipt" — showing exactly how much age, league weight, or goal output added or subtracted from a specific player's price, and which features actually drive value within each market tier.
Turning it into a decision tool
The project closes with an interactive arbitrage simulator: adjust a player's technical profile and league tier, and it instantly projects the valuation gap between their current market and a higher one — the kind of what-if a sporting director would actually ask before making an offer.
What the segmented approach exposed
- Simpler beat sophisticated. Ridge Regression matched or outperformed XGBoost and Random Forest in most market tiers — once the market was properly segmented, extra model complexity added little.
- The mass market has a ceiling. The tier covering ~80% of all players plateaued around R² 0.44 even after cleaning and tuning — an honest limit that says as much about how unpredictable average-player pricing is as it does about the model.
- Geography and age outweigh most stats.
league_weightandage_at_valuationwere consistently the two strongest price drivers across every tier, in both feature-importance and SHAP analysis. - Isolating noise stabilized the top tier. Using Isolation Forest to separate a noisy sub-segment rather than forcing one model to fit everyone took that tier from unreliable to a consistent R² above 0.60.
Instead of one black-box number, this gives clubs and scouts a segmented, explainable pricing engine that's honest about where its confidence is high — proven veterans and superstars — and where the market itself is inherently noisier. The project was assessed at a perfect 120/120. This project is still evolving: the next iteration will move from pooling 2021–2026 valuations together to comparing prices strictly year over year, so the model reflects how the market actually moves over time rather than treating five years of data as one snapshot.