The Players
Nikki and myself (Alex Kaechele)
The Game
Players take turns selecting Champions League Teams. These teams will earn points throughout the game. The goal is to win the most rounds (Group Stage, Round of 16, Quarterfinals, Semifinals, and Championship)
Drafting Process
Drafting: The first person selects a team. The second player chooses two teams (to mitigate the first player advantage), and then the two players alternate picks until all 32 teams are chosen.
Point System
Group Stage: Players win two points for each team getting first in their group. Players get one point for every team getting second in their group. No points are awarded for getting third or fourth in the group.
Elimination Rounds: Players get 1 point for every team that wins a game in each stage.
Nikki chose first followed by me. These were our selected teams:
# Loading in Selected Teams
require(data.table)
library(knitr)
library(kableExtra)
data.table(`Nikki's Teams` = c("Bayern Munich", "Barcelona", "Tottenham", "Napoli", "Ajax", "Porto", "Man United", "PSV", "CSKA Moscow", "Young Boys", "Galatasaray", "Club Brugge", "Hoffenheim", "Monaco", "AEK Athens", "Viktoria Plzen"),
`Alex's Teams` = c("Man City", "Real Madrid", "Liverpool", "Juventus", "Atletico Madrid", "PSG", "Dortmund","Inter Milan", "Roma", "Lyon", "Valencia", "Benfica", "Shakhtar", "Schalke_04", "Red Star","Lokomotiv")) %>%
kable() %>%
kable_styling("striped", full_width = F) %>%
#column_spec(1, bold=T) %>%
row_spec(0, bold = T, color = "white", background = "#5e78d6") | Nikki’s Teams | Alex’s Teams |
|---|---|
| Bayern Munich | Man City |
| Barcelona | Real Madrid |
| Tottenham | Liverpool |
| Napoli | Juventus |
| Ajax | Atletico Madrid |
| Porto | PSG |
| Man United | Dortmund |
| PSV | Inter Milan |
| CSKA Moscow | Roma |
| Young Boys | Lyon |
| Galatasaray | Valencia |
| Club Brugge | Benfica |
| Hoffenheim | Shakhtar |
| Monaco | Schalke_04 |
| AEK Athens | Red Star |
| Viktoria Plzen | Lokomotiv |
Prediction Data
To get a sense of who was winning. I web-scraped data from FiveThirtyEight to get probabilities of each team making it to a given round. Multiplying those probables times the number of points each position was worth gave me a round by round expected score.
Group Stage Expected Scores
Here is how the Group Stage is expected to finish:
# Loading Packages
library(rvest)
library(qdapRegex)
library(gsubfn)
library(ggplot2)
# URL for fivethirtyeight data
url <- 'https://projects.fivethirtyeight.com/soccer-predictions/champions-league/'
#session <- html_session(url)
#form <- html_form(read_html(url))[[1]]
#filled_form <- set_values(form, searchby = 'Your username here', keys = 'Your password here')
# Loading the HTML code from website
webpage <- read_html(url)
# Getting probabilities of reaching certain rounds
predictions <- NULL
for (i in 1:32){
predictions <- rbind(predictions, (html_nodes(webpage,'.champ') %>% html_attr("data-val"))[(1+i*8):(8+i*8)])
}
# Making the table a data frame
predictions <- as.data.frame(predictions)
# Making everything numeric
predictions = as.data.frame(sapply(predictions, function(x) as.numeric(as.character(x))))
# Getting rows (with team names)
rownames(predictions) <- html_nodes(webpage, ".team-row .champ-win , .team-row .drop-3 , .team-row .drop-7 , .team-row .drop-4 , .team-row .champ-group3 , .team-row .champ-group2 , .border-left , .team-row .team") %>%
html_attr("data-str") %>%
na.omit() %>%
as.character() %>%
gsub(pattern = " ", replacement = "_") %>%
gsub(pattern = ".", replacement = "", fixed = TRUE)
# naming columns (with predicted round)
names(predictions) <- html_nodes(webpage,'.lower .champ') %>%
rm_between("\">", '</', extract=TRUE) %>%
unlist() %>%
gsub(pattern = " ", replacement = "_") %>%
gsub(pattern = "1st", replacement = "first") %>%
gsub(pattern = "2nd", replacement = "second") %>%
gsub(pattern = "3rd", replacement = "third")
# Loading in Selected Teams
alex_teams <- c("man_city", "real_madrid", "liverpool", "juventus", "atletico_madrid", "psg", "dortmund","inter_milan",
"roma", "lyon", "valencia", "benfica", "shakhtar", "schalke_04", "red_star","lokomotiv")
nikki_teams <- c("bayern_munich", "barcelona", "tottenham", "napoli", "ajax", "porto", "man_united", "psv", "cska_moscow",
"young_boys", "galatasaray", "club_brugge", "hoffenheim", "monaco", "aek_athens", "viktoria_plzen")
# nikki group stage score
data.table("Round" = c("Group Stage"),
"Nikki" = sum(predictions[row.names(predictions) %in% nikki_teams,]$first*2 + predictions[row.names(predictions) %in% nikki_teams,]$second),
"Alex" = sum(predictions[row.names(predictions) %in% alex_teams,]$first*2 + predictions[row.names(predictions) %in% alex_teams,]$second)) %>%
kable() %>%
kable_styling("striped", full_width = F) %>%
column_spec(1, bold=T) %>%
row_spec(0, bold = T, color = "white", background = "#5e78d6") | Round | Nikki | Alex |
|---|---|---|
| Group Stage | 9.178 | 14.822 |
What Teams are Paying Off?
Here is how each team is expected to contribute to the group stage score:
# nikki top performers
nikki_team_scores <- cbind(team = rownames(predictions)[rownames(predictions) %in% nikki_teams],
score = predictions[row.names(predictions) %in% nikki_teams,]$first*2 + predictions[row.names(predictions) %in% nikki_teams,]$second) %>%
data.table()
# alex top performers
alex_team_scores <- cbind(team = rownames(predictions)[rownames(predictions) %in% alex_teams],
score = predictions[row.names(predictions) %in% alex_teams,]$first*2 + predictions[row.names(predictions) %in% alex_teams,]$second) %>%
data.table()
cbind(nikki_team_scores[order(as.numeric(score), decreasing = TRUE)] %>% dplyr::rename(., "Nikki's Team" = "team"),
alex_team_scores[order(as.numeric(score), decreasing = TRUE)] %>% dplyr::rename(., "Alex's Team" = "team")) %>%
kable() %>%
kable_styling("striped", full_width = F) %>%
column_spec(1, bold=T) %>%
column_spec(3, bold=T) %>%
row_spec(0, bold = T, color = "white", background = "#5e78d6")| Nikki’s Team | score | Alex’s Team | score |
|---|---|---|---|
| barcelona | 1.7582 | juventus | 1.7995 |
| bayern_munich | 1.63325 | man_city | 1.6162 |
| porto | 1.34625 | real_madrid | 1.6126 |
| ajax | 0.8565 | atletico_madrid | 1.6059 |
| man_united | 0.7615 | dortmund | 1.25605 |
| napoli | 0.75415 | liverpool | 1.21335 |
| cska_moscow | 0.67425 | psg | 1.01365 |
| galatasaray | 0.62575 | inter_milan | 1.0028 |
| hoffenheim | 0.2118 | schalke_04 | 0.96675 |
| tottenham | 0.15385 | lyon | 0.89135 |
| young_boys | 0.11835 | roma | 0.6833 |
| club_brugge | 0.1097 | benfica | 0.47915 |
| psv | 0.08515 | valencia | 0.32065 |
| aek_athens | 0.0311 | shakhtar | 0.28065 |
| viktoria_plzen | 0.02985 | lokomotiv | 0.06125 |
| monaco | 0.02835 | red_star | 0.01885 |
Distribution of Team Expected Score
Here are the Group Stage expected score distributions:
dat <- data.frame(cbind(person = append(rep("Nikki", 16), rep("Alex", 16)),
score = append(nikki_team_scores$score, alex_team_scores$score)), stringsAsFactors = FALSE)
dat$score <- as.numeric(dat$score)
dat$person <- as.factor(dat$person)
wdat <- dat %>% dplyr::group_by(person) %>% dplyr::summarize(avscore = mean(score))
ggplot(dat, aes(x = score)) + geom_density(aes(fill = person), alpha = 0.4) +
geom_vline(data = wdat, aes(xintercept = avscore, color = person), linetype = "dashed") +
ylab('Density') + xlab('Expected Score') + ggtitle("CL Team Expected Score Distribution") +
theme_classic()