Predictive Hacks

Who is going to Win the Euro 2020

euro_2021 knockout

We have reached the knock-out phase of Euro 2020 (or 2021) where the final-16 teams and the games can be shown below:

The question is who is going to be the Euro 2020 Winner. Although we cannot predict the Winner, we can estimate the probabilities of each team to win the Euro.

The Methodology

This is a very simple model that is based on FIFA Ranking. Our assumption is that each team follows the Normal Distribution, with mean its corresponding ranking and standard deviation the (max ranking – min ranking)/6. Regarding the standard deviation, we assumed that the UEFA teams are coming from the same distribution where the standard deviation can be estimated from the 6 sigma rule.

UEFA Ranking

Finally, once we define the distribution of each team, we will simulate the results of Round 16 and we will estimate the Winner.

The Code

We will work in R and we will run 10000 simulations.

# get the UEFA Ranking


ranking<-list(bel=1783,
fra=1757,
eng=1687,
por=1666,
esp=1648,
ita=1642,
den=1632,
ger=1609,
sui=1606,
cro=1606,
net=1598,
wal=1570,
swe=1570,
aus=1523,
ukr=1515,
cze=1459)


# get the range of the max UEFA ranking (Belgium) minus the minimum (San Marino) and devide it by 6
# assuming that 6 sigma is the range 
stdev<-(1783-805)/6

sim_champion<-c()

for (i in 1:10000) {

#######################
#### Final 16
#######################

# game bel vs por
teams_game1<-c("bel","por")
game1<-rnorm(1, ranking[[teams_game1[1]]], stdev)>rnorm(1, ranking[[teams_game1[2]]], stdev)
if (game1) {
  qualified_game1<-teams_game1[1] 
  } else {
  qualified_game1<-teams_game1[2]}

qualified_game1


# game ita vs aus
teams_game2<-c("ita","aus")
game2<-rnorm(1, ranking[[teams_game2[1]]], stdev)>rnorm(1, ranking[[teams_game2[2]]], stdev)
if (game2) {
  qualified_game2<-teams_game2[1] 
} else {
  qualified_game2<-teams_game2[2]}

qualified_game2


# game fra vs sui
teams_game3<-c("fra","sui")
game3<-rnorm(1, ranking[[teams_game3[1]]], stdev)>rnorm(1, ranking[[teams_game3[2]]], stdev)
if (game3) {
  qualified_game3<-teams_game3[1] 
} else {
  qualified_game3<-teams_game3[2]}

qualified_game3


# game cro vs esp
teams_game4<-c("cro","esp")
game4<-rnorm(1, ranking[[teams_game4[1]]], stdev)>rnorm(1, ranking[[teams_game4[2]]], stdev)
if (game4) {
  qualified_game4<-teams_game4[1] 
} else {
  qualified_game4<-teams_game4[2]}

qualified_game4



# game swe vs ukr
teams_game5<-c("swe","ukr")
game5<-rnorm(1, ranking[[teams_game5[1]]], stdev)>rnorm(1, ranking[[teams_game5[2]]], stdev)
if (game5) {
  qualified_game5<-teams_game5[1] 
} else {
  qualified_game5<-teams_game5[2]}

qualified_game5


# game eng vs ger
teams_game6<-c("eng","ger")
game6<-rnorm(1, ranking[[teams_game6[1]]], stdev)>rnorm(1, ranking[[teams_game6[2]]], stdev)
if (game6) {
  qualified_game6<-teams_game6[1] 
} else {
  qualified_game6<-teams_game6[2]}

qualified_game6


# game net vs cze
teams_game7<-c("net","cze")
game7<-rnorm(1, ranking[[teams_game7[1]]], stdev)>rnorm(1, ranking[[teams_game7[2]]], stdev)
if (game7) {
  qualified_game7<-teams_game7[1] 
} else {
  qualified_game7<-teams_game7[2]}

qualified_game7


# game wal vs den
teams_game8<-c("wal","den")
game8<-rnorm(1, ranking[[teams_game8[1]]], stdev)>rnorm(1, ranking[[teams_game8[2]]], stdev)
if (game8) {
  qualified_game8<-teams_game8[1] 
} else {
  qualified_game8<-teams_game8[2]}

qualified_game8



#######################
#### Final 8
#######################

teams_f8_1<-c(qualified_game1,qualified_game2)
game_f8_1<-rnorm(1, ranking[[teams_f8_1[1]]], stdev)>rnorm(1, ranking[[teams_f8_1[2]]], stdev)

if (game_f8_1) {
  qualified_f8_1<-teams_f8_1[1] 
} else {
  qualified_f8_1<-teams_f8_1[2]}

qualified_f8_1


teams_f8_2<-c(qualified_game3,qualified_game4)
game_f8_2<-rnorm(1, ranking[[teams_f8_2[1]]], stdev)>rnorm(1, ranking[[teams_f8_2[2]]], stdev)

if (game_f8_2) {
  qualified_f8_2<-teams_f8_2[1] 
} else {
  qualified_f8_2<-teams_f8_2[2]}

qualified_f8_2


teams_f8_3<-c(qualified_game5,qualified_game6)
game_f8_3<-rnorm(1, ranking[[teams_f8_3[1]]], stdev)>rnorm(1, ranking[[teams_f8_3[2]]], stdev)

if (game_f8_3) {
  qualified_f8_3<-teams_f8_3[1] 
} else {
  qualified_f8_3<-teams_f8_3[2]}

qualified_f8_3


teams_f8_4<-c(qualified_game7,qualified_game8)
game_f8_4<-rnorm(1, ranking[[teams_f8_4[1]]], stdev)>rnorm(1, ranking[[teams_f8_4[2]]], stdev)

if (game_f8_4) {
  qualified_f8_4<-teams_f8_4[1] 
} else {
  qualified_f8_4<-teams_f8_4[2]}

qualified_f8_4


#######################
#### Final 4
#######################

teams_f4_1<-c(qualified_f8_1,qualified_f8_2)
game_f4_1<-rnorm(1, ranking[[teams_f4_1[1]]], stdev)>rnorm(1, ranking[[teams_f4_1[2]]], stdev)

if (game_f4_1) {
  qualified_f4_1<-teams_f4_1[1] 
} else {
  qualified_f4_1<-teams_f4_1[2]}

qualified_f4_1


teams_f4_2<-c(qualified_f8_3,qualified_f8_4)
game_f4_2<-rnorm(1, ranking[[teams_f4_2[1]]], stdev)>rnorm(1, ranking[[teams_f4_2[2]]], stdev)

if (game_f4_2) {
  qualified_f4_2<-teams_f4_2[1] 
} else {
  qualified_f4_2<-teams_f4_2[2]}

qualified_f4_2


#######################
#### Final 
#######################

teams_f<-c(qualified_f4_1,qualified_f4_2)
game_f<-rnorm(1, ranking[[teams_f[1]]], stdev)>rnorm(1, ranking[[teams_f[2]]], stdev)

if (game_f) {
  champion<-teams_f[1] 
} else {
  champion<-teams_f[2]}

sim_champion<-c(sim_champion,champion)
}


prop.table(table(sim_champion))*100

The Estimated Results

After running 10,000 simulations, we get that Belgium is the most likely team to win the Euro 2020 with a 25.8% probability followed by France (21%) and England (13%)

TeamProbability (%)
Belgium25.82
France21.17
England13.18
Denmark6.61
Italy5.24
Netherlands5.18
Spain4.74
Portugal4.66
Germany3.76
Sweden2.31
Croatia2.14
Wales2.1
Switzerland1.91
Ukraine0.78
Austria0.22
Czech Republic0.18

The Estimated Odds from the Market/Bookmakers

According to Bookmaker, the favorite to win the trophy is France, followed by Italy and England.

My Suggestion

upload.wikimedia.org/wikipedia/commons/6/65/Fla...

Personally, I see mispricing in Bookmakers’ odds for Belgium that pays off 9 times (meaning an estimated probability to win the euro 11.11%). So my suggestion is to go with Belgium!

Share This Post

Share on facebook
Share on linkedin
Share on twitter
Share on email

1 thought on “Who is going to Win the Euro 2020”

  1. Lol, so much fun, I think you can make it more concise by creating some functions. Here is my way of doing the same:

    # Get the UEFA Ranking
    ranking <- list(
    bel = 1783,
    fra = 1757,
    eng = 1687,
    por = 1666,
    esp = 1648,
    ita = 1642,
    den = 1632,
    ger = 1609,
    sui = 1606,
    cro = 1606,
    net = 1598,
    wal = 1570,
    swe = 1570,
    aus = 1523,
    ukr = 1515,
    cze = 1459
    )

    # Brackets for the round of 16 (the order is important!)
    brackets <- list(
    game1 = c("bel", "por"),
    game2 = c("ita", "aus"),
    game3 = c("fra", "sui"),
    game4 = c("cro", "esp"),
    game5 = c("swe", "ukr"),
    game6 = c("eng", "ger"),
    game7 = c("net", "cze"),
    game8 = c("wal", "den")
    )

    # Range of the max UEFA ranking (Belgium) minus the minimum (San Marino) and
    # divide it by 6 (estimated from the 6 sigma rule)
    stdev <- (1783 – 805) / 6

    simulate_game <- function(team1, team2) {
    get_prob <- function(ranking, sd) {
    rnorm(mean = ranking, sd = sd, n = 1)
    }
    prob1 <- get_prob(ranking[[team1]], sd = stdev)
    prob2 prob2) {
    return(team1)
    } else {
    return(team2)
    }
    }

    # Function to create brackets again, used to create brackets again after
    # obtaining the results from a simulated round
    create_brackets <- function(x) {
    brackets <- vector("list", length(x)/2)
    i <- 1
    for (j in seq_along(brackets)) {
    brackets[[j]] <- c(x[[i]], x[[i+1]])
    i <- i + 2
    }
    brackets
    }

    simulated_champions 1) {
    results <- lapply(brackets, function(game) simulate_game(game[[1]], game[[2]]))
    brackets <- create_brackets(results)
    }
    champion <- simulate_game(unlist(results)[[1]], unlist(results)[[2]])
    champion
    })

    sort(prop.table(table(simulated_champions)) * 100, decreasing = TRUE)

    Reply

Leave a Comment

Subscribe To Our Newsletter

Get updates and learn from the best

More To Explore

Python

Image Captioning with HuggingFace

Image captioning with AI is a fascinating application of artificial intelligence (AI) that involves generating textual descriptions for images automatically.

Python

Intro to Chatbots with HuggingFace

In this tutorial, we will show you how to use the Transformers library from HuggingFace to build chatbot pipelines. Let’s