Primjer kako napraviti nekoliko osnovnih analiza o Fantasy Premier League. Za početak, treba nam R Studio, i nekoliko paketića:

library(tidyverse)
library(fplscrapR)

Neću objašnjavati zašto nam je ovo potrebno, detaljnije o ovome imati na jednom mom drugom postu. U svakom slučaju, sljedeći korak nam je dobaviti rezultate. E sad, kako je sve jednostavno dok se ne krene… Koje rezultate? Trebaju li nam možda podaci igračima, menadžerima ili možda o gameweek-ovima? Ovisno o tome što nam treba ćemo koristiti različite naredbe.

Kako Vas ne bih otjerao prije nego li ste i došli, ostanimo za sad na igračima. U nekom od sljedećih postova ću pokazati kako prikazati podatke o menadžerima (koliko bodova po kolu, koliko transfera, tko igra, tko je na klupi, itd.) i kako prikazati podatke o kolu (koliko transfera je napravljeno, koliko wildcard-ova odigrano, itd.).

Kako bismo dobili podatke o igračima, koristit ćemo sljedeću naredbu:

get_player_details()

Vodite računa što radimo tom naredbom. Tražimo FPL stranicu da nam pošalje bazu podataka u kojoj se nalaze informacije o (cca) 600tinjak igrača (otprilike 30ak po ekipi) i njihovi rezultati do ovog kola (u trenutku pisanja, usred 19. kola smo).

igraci=get_player_details()

Dakle, to će biti ooogromna tablica, za koju je mom kompjuteru (viša srednja klasa) trebalo 2-3 minute da skine tu bazu u kojoj se nalazi 11272 retka i 37 stupca (varijabli). Puno, previše. Hajmo prvo malo samo urediti tu bazu. Da bismo krenuli, provjerimo što se sve nalazi u bazi:

igraci %>%
  colnames()
##  [1] "element"                    "fixture"                   
##  [3] "opponent_team"              "total_points"              
##  [5] "was_home"                   "kickoff_time"              
##  [7] "team_h_score"               "team_a_score"              
##  [9] "round"                      "minutes"                   
## [11] "goals_scored"               "assists"                   
## [13] "clean_sheets"               "goals_conceded"            
## [15] "own_goals"                  "penalties_saved"           
## [17] "penalties_missed"           "yellow_cards"              
## [19] "red_cards"                  "saves"                     
## [21] "bonus"                      "bps"                       
## [23] "influence"                  "creativity"                
## [25] "threat"                     "ict_index"                 
## [27] "starts"                     "expected_goals"            
## [29] "expected_assists"           "expected_goal_involvements"
## [31] "expected_goals_conceded"    "value"                     
## [33] "transfers_balance"          "selected"                  
## [35] "transfers_in"               "transfers_out"             
## [37] "playername"

Neke varijable su mi jasne (npr., transfers_in vjerojatno sadrži informaciju o broju transfera igrača u gameweek-u), ili round pretpostavljam da je naziv za gameweek, dok mi neke i nisu baš jasne, npr. što je to element? Pa da ne bismo nagađali, pogledajmo koje vrijednosti se pojavljuju u varijabli element:

igraci %>% 
  select(playername,element) %>% 
  sample_n(.,10) %>% 
  head()
## # A tibble: 6 x 2
##   playername                element
##   <chr>                       <dbl>
## 1 Malcolm Ebiowei               173
## 2 Maxwel Cornet                 575
## 3 Terence Kongolo               208
## 4 Ederson Santana de Moraes     307
## 5 Jamie Vardy                   255
## 6 Ryan Fraser                   359

Meni se čini (a i provjerio sam, tako da sad i znam) da se radi o šifri igrača, a dobili su je na način da su klubovi poredani abecedeno (Arsenal, …), i unutar kluba su igrači poredani abecedno pa tako (Cedric Soares ima šifru 1). Ako bolje promotrimo kojih sve varijabli imamo, primjetit ćemo da ne postoji podatak o poziciji igrača, kao ni o klubu za koji igrači igraju…

Eto prilika za jedan budući post kako doći do tih informacija. U svrhu ne-kompliciranja, zadržimo se gdje smo trenutno - dakle imamo samo informacije o igraču, odnosno o njegovom učinku po pojedinom kolu. Recimo da nas ne zanimaju igrači koji do sad nisu odigrali ni minute, pa ćemo njih izbaciti iz baze:

igraci_koji_igraju=
  igraci %>% 
  group_by(playername) %>% 
  mutate(minute=sum(minutes)) %>%
  filter(minute>90) %>% 
  ungroup

Pala knjiga na manje slova, ne znam točno koliko ali više nemam 11 tisuća redova (cca 30ak igrača x 20 klubova x 19 kola = 11 tisuća), nego cca 7000 redova, drugim riječima, oko 18 igrača po klubu je ostalo koji su ukupno odigrali barem 90 minuta u ovih 19 kola.

Opet smo na raskrižju, što nas zanima, učinak igrača od kola do kola, ili sažetak učinka do sad, do 19og kola? Možemo za prvu ruku pogledati kako je Haaland igrao ovih 19 kola i usporediti njegove bodove sa recimo Salahovim bodovima:

igraci_koji_igraju %>% 
  filter(playername %in% c("Erling Haaland", "Mohamed Salah")) %>% 
  select(playername,goals_scored,total_points,round) %>% 
  ggplot(aes(x=round,y=total_points,color=playername))+
  geom_point(show.legend = F,size=2.5)+
  geom_line(size=1)+
  scale_color_manual(values = c("lightblue","red"))+
  labs(x="Gameweek",
       y="Broj bodova u kolu",
       color="Igrač")+
  cowplot::theme_cowplot()

Eto, nije neki specijalni graf, i to smo i znali, ali vidimo ovdje da Haaland zaista ostvaruje više bodova po kolu. Što se još vidi, slično su počeli, kod obojice mi se čini da ta linija skakuće (kolo dobro, pa jedno loše, kolo dobro, pa jedno loše,…)).

Provjerimo je li sličan obrazac obzirom na to igraju li kod kuće ili vani. Ponovit ćemo sve analize uz uvjet da dobijemo 2 slike. Jednu za kod kuće a drugi na strani:

igraci_koji_igraju %>% 
  filter(playername %in% c("Erling Haaland", "Mohamed Salah")) %>% 
  select(playername,goals_scored,total_points,round,was_home) %>% 
  ggplot(aes(x=round,y=total_points,color=playername))+
  geom_point(show.legend = F,size=2.5)+
  geom_line(size=1)+
  scale_color_manual(values = c("lightblue","red"))+
  labs(x="Gameweek",
       y="Broj bodova u kolu",
       color="Igrač")+
  facet_wrap(~was_home)+
  cowplot::theme_cowplot()

Teško mi je nešto smisleno komentirati na ovom grafu. Definitivno ono što je očito je da Haaland obožava igrati kod kuće (TRUE je odgovor na ime varijable was_home?, dakle TRUE je kad su kod kuće), dok Saki je rekordan broj bodova ove sezone (12 i 15 bodova) ostvario vani.

Tek sam sad vidio da (od ove godine) postoji i metrika xG i xA. Pa provjerimo koliko je xG valjana mjera, odnosno koliko dobro njome možemo predvidjeti broj golova nekolicine top igrača. Ja sam upravo odlučio da to budu: KDB, Mo, Kane, Rashford, Erling, Toney, Mitrović, Sterling, Mount, Almiron, Jesus, Martinelli, Kuluševski, Wilson i to je to:

igraci_koji_igraju %>% 
  filter(playername %in% c("Erling Haaland",
                           "Mohamed Salah",
                           "Kevin De Bruyne",
                           "Raheem Sterling",
                           "Harry Kane",
                           "Marcus Rashford",
                           "Ivan Toney",
                           "Aleksandar Mitrović",
                           "Mason Mount",
                           "Miguel Almirón Rejala",
                           "Callum Wilson",
                           "Martinelli",
                           "Dejan Kulusevski",
                           "Darwin")) %>%
  select(playername,goals_scored,total_points,round,expected_goals) %>%
  mutate(expected_goals=as.numeric(expected_goals)) %>%
  group_by(playername) %>% 
  summarise(points=sum(total_points,na.rm = T),
            goals=sum(goals_scored,na.rm = T),
            xG=sum(expected_goals,na.rm = T)) %>% 
  ungroup() %>%
  ggplot(aes(x=xG,y=goals,color=playername))+
  geom_point(show.legend = F,size=2.5)+
  geom_abline(intercept = 0, slope = 1)+
  ggrepel::geom_label_repel(aes(label = playername),show.legend = F)+
  labs(x="xG",
       y="Broj golova (do 19. kola)")+
  cowplot::theme_cowplot()

Ono što je vidljivo tu na grafu da se radi o “over-performerima”. Izuzev Mo-a i Darwina, koji su malo podbacili. Jedna mala napomena za bilo koga tko planira ponoviti moje analize… 2 sata pokušavam riješiti problem Darwin Nunezovog imena. Zbog #@!*& slova “ñ” nikako ga naći u bazi. Tako da sam morao izvaditi bazu u dobri stari Excel, naći ga tamo i preimenovati ga u jednostavno Darwin. Ako itko bude htio ponavljati ove analize, klonite se Darwina…

U svakom slučaju xG je očito valjana mjera, u smislu da čim veći očekivani broj golova - to veći broj zabijenih golova. Malo me samo muči koji su igrači debelo pobacili - u smislu da su zabili puno manje golova od predviđenog xG-em:

igraci_koji_igraju %>% 
  select(playername,goals_scored,total_points,round,expected_goals) %>%
  mutate(expected_goals=as.numeric(expected_goals)) %>%
  group_by(playername) %>% 
  summarise(points=sum(total_points,na.rm = T),
            goals=sum(goals_scored,na.rm = T),
            xG=sum(expected_goals,na.rm = T)) %>% 
  ungroup() %>%
  mutate(razlika=goals-xG,
         playername=as.character(playername)) %>% 
  arrange(razlika) %>%
  head() %>% 
  ggplot(aes(x=reorder(playername,razlika),y=razlika,fill=playername))+
  geom_col(position="dodge",show.legend = F)+
  scale_y_reverse()+
  coord_flip()+
  labs(x="",
       y="Zabijeni golovi - xG")+
  cowplot::theme_cowplot()

Dakle, ovdje sam izračunao razliku između očekivanog i zabijenog broja golova. Dobrom starom Patricku ćemo oprostiti, ozljeda ga je sputala da ne ostvari svoj potencijal, no Bowen, Welback, čak i Jesus koji je nešto golova su kratki cca 3 gola… Što realno nije puno, ali vodeći se onom starom da je forma prolazna, a klasa vječna - samo je pitanje vremena kad će doktori početi trpati!

Za kraj, pogledajmo tko bi predvodio gornju listu ako pogledamo samo one igrače koji su zabili makar 3 gola:

igraci_koji_igraju %>% 
  select(playername,goals_scored,total_points,round,expected_goals) %>%
  mutate(expected_goals=as.numeric(expected_goals)) %>%
  group_by(playername) %>% 
  summarise(points=sum(total_points,na.rm = T),
            goals=sum(goals_scored,na.rm = T),
            xG=sum(expected_goals,na.rm = T)) %>% 
  ungroup() %>%
  filter(goals>3) %>% 
  mutate(razlika=goals-xG,
         playername=as.character(playername)) %>% 
  arrange(razlika) %>%
  head() %>% 
  ggplot(aes(x=reorder(playername,razlika),y=razlika,fill=playername))+
  geom_col(position="dodge",show.legend = F)+
  scale_y_reverse()+
  coord_flip()+
  labs(x="",
       y="Zabijeni golovi - xG")+
  cowplot::theme_cowplot()

Još se eventualno Mo ugurao, ostali su više-manje točno tamo gdje im xG i predviđa da jesu!

Do sljedećeg puta, nadam se da smo nešto naučili!