Overview

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.


The Picks

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


Who’s Winning?

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()