World Cup 2026 Group Stages

Here I would like to explore the effect of different variables on the performance of different countries in the group stage of the World Cup (2026)!

Getting Data

First I gathered some data from various sources including fotmob and sofascore, and read it into R:

# Libraries
library(tidyverse)
library(ggimage)

# Set wd
data <- read.csv('Group-Stage.csv')

# View data
knitr::kable(head(data))

# Edit data
data$xGDiff <- data$xG - data$xGA
Team Points GoalDiff xG xGA Population StartingValue GDP Code
Algeria 4 -2 3.9 3.4 47.4 181.3 5.364 dz
Argentina 9 7 5.7 1.6 46.7 407.4 14.187 ar
Australia 4 0 2.1 2.7 28.2 53.2 67.129 hm
Austria 4 0 3.7 4.5 9.2 112.9 56.142 at
Belgium 5 4 6.8 1.9 11.8 248.8 55.049 be
Bosnia 4 -1 1.9 4.1 3.1 93.2 8.639 ba

Plotting Data

Next I wanted to plot some of this data to investigate it:

# Plot: GDP
ggplot(data=data, aes(y=xGDiff, x=log10(GDP)))+
  geom_point()+
  geom_smooth(method=lm, se=FALSE, colour='black', linetype='dotted', size=0.75) +
  geom_image(data=data, aes(y=xGDiff, x=log10(GDP), image=Image))+
  theme+
  labs(title='Effect of GDP on xG Difference', x='Log10 GDP per capita ($)', y='xG - xGA')

# Plot: population
ggplot(data, aes(y=xGDiff, x=log10(Population)))+
  geom_point()+
  geom_smooth(method=lm, se=FALSE, colour='black', linetype='dotted', size=0.75) +
  geom_image(data=data, aes(y=xGDiff, x=log10(Population), image=Image))+
  theme+
  labs(title='Effect of Population on xG Difference', x='Log10 Population (Millions)', y='xG - xGA')

# Plot: starting value
ggplot(data, aes(y=xGDiff, x=StartingValue))+
  geom_point()+
  geom_smooth(method=lm, se=FALSE, colour='black', linetype='dotted', size=0.75) +
  geom_image(data=data, aes(y=xGDiff, x=StartingValue, image=Image))+
  theme+
  labs(title='Effect of Starting XI Value on xG Difference', x='Starting XI Value (Millions)', y='xG - xGA')

Analysing Data

From these plots I can see that country population, GDP per capita and the market value of the starting XI all positively affect how each country performed in the group stages of the world cup. I can also quantify this using a linear regression model for each variable:

# Linear regression model
model <- lm(xGDiff ~ GDP+Population+StartingValue, data=data)
knitr::kable(head(summary(model)$coefficients))

# Linear regression model for each variable alone
summary(lm(xGDiff ~ GDP, data=data))$r.squared
summary(lm(xGDiff ~ Population, data=data))$r.squared
summary(lm(xGDiff ~ StartingValue, data=data))$r.squared
Estimate Std. Error t value Pr(>|t|)
(Intercept) -2.7769163 0.6434115 -4.3159260 0.0000887
GDP 0.0048872 0.0142379 0.3432515 0.7330440
Population 0.0123690 0.0060656 2.0392130 0.0474630
StartingValue 0.0097039 0.0018155 5.3449376 0.0000031
## [1] 0.04071865
## [1] 0.110686
## [1] 0.4326861

Analysing Data

From this analysis (and the graphs) I can see that the market value of the starting XI has the largest effect on performance in the group stages: in the combined model it has a very small p-value (indicating that it is unlikely to observe a relationship between the predictor and outcome due to chance), and alone it explains ~43% of the variance in xG difference. Meanwhile, GDP and Population explain ~4% and ~11% of the variance in xG difference.

There are also some points of interest: Canada, Switzerland and Mexico have performed very well in the group stages despite having a relatively low starting XI market value, meanwhile Sweden, Croatia and Portugal have done a little worse than might be expected. Also, although France has by far the highest value team (€912.3M), they did not perform as well as several countries including Switzerland (€162.8M), Belgium (€248.8M) and Canada (€98.7M). However it is important to note that group difficulty will influence these metrics.

It is also interesting to look at the relationships between GDP, population and starting value:

# Plots
ggplot(data=data, aes(y=StartingValue, x=log10(Population)))+
  geom_point()+
  geom_smooth(method=lm, se=FALSE, colour='black', linetype='dotted', size=0.75) +
  geom_image(data=data, aes(y=StartingValue, x=log10(Population), image=Image))+
  theme+
  labs(title='Effect of Population on Starting XI Value')

summary(lm(StartingValue ~ Population, data=data))$r.squared
## [1] 0.03078913

Population only explains ~3% of the variance in starting XI market value, with some very populuous countries having a relatively low market value (such as the USA, Japan and Mexico) and less populous countries having a much higher value (such as Uruguay, Croatia and Norway). This may be due to the presence of one very highly valued player in some of these countries, such as Erling Haaland for Norway or Federico Valverde for Uruguay.