Skąd padają gole? Jak poruszają się piłkarze podczas meczu? Czy zawodnicy podają zawsze do tych samych?
Wszystkiego tego można się dowiedzieć jak tylko ma się odpowiednie dane… Warto przeglądać czasem Reddita – można znaleźć np. Soccer shots dataset (post już jest skasowany, ale kto pierwszy ten lepszy) zawierający link do arkusza z danymi zeskrapowanymi z ciekawej strony understat.com.
Skoro ktoś zdjął te dane i udało mi się zapisać do nich link to wykorzystajmy je!
W pierwszej kolejności musimy pobrać dane z Google Drive – lepiej mieć niż nie mieć ;)
1 2 3 4 5 6 7 8 9 10 11 12 |
# Będziemy potrzebowac standardowo pakietów: library(tidyverse) library(janitor) library(igraph) # a żeby pobrac dane z Google Drive wystarczy: library(googledrive) "1yeIl0rZldsmmRzdGUkG56QmX7UXI0PHQ" %>% as_id() %>% drive_get() %>% drive_download(path = "xg_master.csv") |
I w pliczku xg_master.csv mamy interesujące nas dane. Zobaczmy co mamy w środku:
1 2 3 4 |
data <- read_csv("xg_master.csv") %>% clean_names() %>% mutate(player = stringi::stri_enc_tonative(player), assist_player = stringi::stri_enc_tonative(assist_player)) |
Po standardowych glimpse() wiemy co i jak, na przykład wiemy że dane pochodzą z kilku sezonów i obejmują ligi europejskie z następującymi drużynami:
1 2 3 4 5 6 7 8 9 10 |
data %>% distinct(league, team) %>% group_by(league) %>% arrange(team) %>% mutate(n = row_number()) %>% ungroup() %>% spread(league, team, fill = "") %>% select(-n) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
Bundesliga | EPL | La_Liga | Ligue_1 | RFPL | Serie_A |
---|---|---|---|---|---|
Augsburg | Arsenal | Alaves | Amiens | Amkar | AC Milan |
Bayer Leverkusen | Aston Villa | Almeria | Angers | Anzhi Makhachkala | Atalanta |
Bayern Munich | Bournemouth | Athletic Club | Bordeaux | Arsenal Tula | Benevento |
Borussia Dortmund | Brighton | Atletico Madrid | Caen | CSKA Moscow | Bologna |
Borussia M.Gladbach | Burnley | Barcelona | Dijon | Dinamo Moscow | Cagliari |
Darmstadt | Cardiff | Celta Vigo | Evian Thonon Gaillard | FC Krasnodar | Carpi |
Eintracht Frankfurt | Chelsea | Cordoba | GFC Ajaccio | FC Orenburg | Cesena |
FC Cologne | Crystal Palace | Deportivo La Coruna | Guingamp | FC Rostov | Chievo |
Fortuna Duesseldorf | Everton | Eibar | Lens | FC Ufa | Crotone |
Freiburg | Fulham | Elche | Lille | FC Yenisey Krasnoyarsk | Empoli |
Hamburger SV | Huddersfield | Espanyol | Lorient | FK Akhmat | Fiorentina |
Hannover 96 | Hull | Getafe | Lyon | Krylya Sovetov Samara | Frosinone |
Hertha Berlin | Leicester | Girona | Marseille | Kuban Krasnodar | Genoa |
Hoffenheim | Liverpool | Granada | Metz | Lokomotiv Moscow | Inter |
Ingolstadt | Manchester City | Las Palmas | Monaco | Mordovya | Juventus |
Mainz 05 | Manchester United | Leganes | Montpellier | Rubin Kazan | Lazio |
Nuernberg | Middlesbrough | Levante | Nancy | SKA-Khabarovsk | Napoli |
Paderborn | Newcastle United | Malaga | Nantes | Spartak Moscow | Palermo |
RasenBallsport Leipzig | Norwich | Osasuna | Nice | Tom Tomsk | Parma |
Schalke 04 | Queens Park Rangers | Rayo Vallecano | Nimes | Torpedo Moscow | Parma Calcio 1913 |
VfB Stuttgart | Southampton | Real Betis | Paris Saint Germain | Tosno | Pescara |
Werder Bremen | Stoke | Real Madrid | Reims | Ural | Roma |
Wolfsburg | Sunderland | Real Sociedad | Rennes | Zenit St. Petersburg | Sampdoria |
Swansea | Real Valladolid | Saint-Etienne | Sassuolo | ||
Tottenham | SD Huesca | SC Bastia | SPAL 2013 | ||
Watford | Sevilla | Strasbourg | Torino | ||
West Bromwich Albion | Sporting Gijon | Toulouse | Udinese | ||
West Ham | Valencia | Troyes | Verona | ||
Wolverhampton Wanderers | Villarreal |
Jedna kolumna określa nam skuteczność strzału, a druga – sytuację. możemy więc zobaczyć…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# skąd co pada? data %>% ggplot() + geom_point(aes(x_coordinate, y_coordinate, color = situation), alpha = 0.7, size = 0.5, show.legend = FALSE) + facet_grid(situation~result) + # boisko xlim(c(0, 1)) + ylim(c(0, 1)) + geom_rect(aes(xmin = 0, ymin = 0, xmax = 1, ymax = 1), fill = NA, color = "black") + geom_rect(aes(xmin = 0, ymin = 0, xmax = 0.5, ymax = 1), fill = NA, color = "black") + geom_rect(aes(xmin = 0, ymin = 0.2, xmax = 0.157, ymax = 0.8), fill = NA, color = "black") + geom_rect(aes(xmin = 1, ymin = 0.2, xmax = 1-0.157, ymax = 0.8), fill = NA, color = "black") + labs(title = "Skąd padają strzały?", x = "", y = "") + theme_void() |
Prześledźmy na szybko rozkład informacji w kolumnach kategorycznych:
1 2 3 |
data %>% count(result, sort = TRUE) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
result | n |
---|---|
MissedShots | 99454 |
BlockedShot | 61410 |
SavedShot | 58449 |
Goal | 25919 |
ShotOnPost | 4797 |
OwnGoal | 770 |
1 2 3 |
data %>% filter(result == "Goal") %>% count(shot_type, sort = TRUE) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
shot_type | n |
---|---|
RightFoot | 13841 |
LeftFoot | 7471 |
Head | 4449 |
OtherBodyPart | 158 |
1 2 3 |
data %>% filter(result == "Goal") %>% count(situation, sort = TRUE) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
situation | n |
---|---|
OpenPlay | 18237 |
FromCorner | 3057 |
Penalty | 2233 |
SetPiece | 1654 |
DirectFreekick | 738 |
1 2 3 |
data %>% filter(result == "Goal") %>% count(preceding_action, sort = TRUE) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
preceding_action | n |
---|---|
Pass | 7119 |
Cross | 4594 |
Standard | 2971 |
Rebound | 2292 |
None | 2232 |
Throughball | 1447 |
TakeOn | 1412 |
Chipped | 1294 |
HeadPass | 804 |
Aerial | 767 |
BallRecovery | 350 |
BallTouch | 238 |
LayOff | 153 |
Dispossessed | 108 |
Tackle | 47 |
Interception | 23 |
BlockedPass | 21 |
Foul | 12 |
CornerAwarded | 8 |
GoodSkill | 6 |
Clearance | 3 |
End | 3 |
Goal | 3 |
OffsidePass | 3 |
SubstitutionOn | 3 |
Card | 2 |
Challenge | 2 |
FormationChange | 1 |
Start | 1 |
Ciekawe Tak sobie. Ciekawsze jest to, w której minucie padają gole. Zamiast liczyć jakąś średnią policzmy po prostu sumę bramek, które padły w kolejnych minutach:
1 2 3 4 5 6 7 8 9 10 11 |
data %>% filter(result == "Goal") %>% filter(minute <= 92) %>% count(minute) %>% ggplot() + geom_line(aes(minute, n), color = "green") + geom_smooth(aes(minute, n), color = "lightgreen", alpha = 0.5) + geom_vline(xintercept = c(45, 90)) + labs(title = "Liczba bramek w zależności od minuty meczu", x = "Minuta meczu", y = "Łączna liczba bramek") |
Dlaczego tuż po 45 minucie mamy skok? To gol do szatnii – nieco przedłużona pierwsza połowa i gol w ostatniej chwili.
Niesamowite jest to, że im dłużej trwa mecz tym więcej bramek pada, tzn. więcej bramek pada w późniejszych minutach. Wydawałoby się, że zmęczenie i – czasem – granie na czas dadzą zna oo sobie i więcej będzie goli w pierwszej połowie. A tutaj zonk. W sumie fajny zonk, bo oznacza to tyle że emocje są do końca.
Podzielmy czas na 5-minutowe bloki i sprawdźmy jak w poszczególnych ligach wygląda liczba zdobytych bramek. Tym razem jednak licząc jaki procent bramek z całej ligi wpada w danym bloku:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# bloki po 5 minut, zależność od ligi data %>% filter(result == "Goal") %>% mutate(minute = 5*( minute %/% 5) ) %>% count(minute, league) %>% group_by(league) %>% mutate(n = 100*n/sum(n)) %>% ungroup %>% ggplot() + geom_tile(aes(minute, league, fill = n), color = "gray50") + scale_fill_distiller(palette = "Reds", direction = 1) + geom_vline(xintercept = c(45, 90)) + labs(title = "Procent bramek w meczu zależności od minuty meczu", x = "Minuta meczu", y = "", fill = "Procent bramek w lidze") |
Znowu widać 45 minutę. Szczególnie w angielskiej Premiere League można liczy na emocje. W sumie około 6% (co 16 mecz) to bramka pod koniec I połowy.
Skupmy się na chwilę na konkretnych zawodnikach. Na przykład Neymar (ulubiony piłkarz mojego syna) – czy strzela w Paris Saint Germain lepiej niż w Barcelonie?
1 2 3 4 5 6 7 8 |
data %>% filter(player == "Neymar") %>% filter(result == "Goal") %>% count(date, team) %>% ggplot() + geom_point(aes(date, n, color = team)) + labs(title = "Neymar: Barcelona vs PSG", color = "", x = "", y = "Liczba strzelonych\nbramek w meczu") |
Strzela mniej więcej tak samo jeśli chodzi o liczbę zdobytych bramek w meczu. A czy strzela z innego miejsca? Może trener coś wypracował i zmieniło się ustawienie?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# skąd strzela data %>% filter(player == "Neymar") %>% filter(result == "Goal") %>% ggplot() + geom_point(aes(x_coordinate, y_coordinate, color = team)) + # boisko xlim(c(0, 1)) + ylim(c(0, 1)) + geom_rect(aes(xmin = 0, ymin = 0, xmax = 1, ymax = 1), fill = NA, color = "black") + geom_rect(aes(xmin = 0, ymin = 0, xmax = 0.5, ymax = 1), fill = NA, color = "black") + geom_rect(aes(xmin = 0, ymin = 0.2, xmax = 0.157, ymax = 0.8), fill = NA, color = "black") + geom_rect(aes(xmin = 1, ymin = 0.2, xmax = 1-0.157, ymax = 0.8), fill = NA, color = "black") + labs(title = "Neymar: Barcelona vs PSG", x = "", y = "", color = "") + theme_void() |
To, że czerwonych kropek jest więcej oznacza tylko tyle, że dłużej grał w Barcy. Strzela mniej więcej z tego samego miejsca. No, w PSG ładuje trochę sprzed pola karnego.
Zobaczmy jak inni. Na początek przygotujemy fragment danych – 12 piłkarzy, którzy strzelili najwięcej bramek:
1 2 3 4 5 |
top_strikers <- data %>% filter(result == "Goal") %>% count(player, sort = T) %>% top_n(12, n) %>% pull(player) |
- Lionel Messi
- Cristiano Ronaldo
- Luis Su�rez
- Robert Lewandowski
- Harry Kane
- Edinson Cavani
- Pierre-Emerick Aubameyang
- Sergio Ag�ero
- Alexandre Lacazette
- Gonzalo Higua�n
- Mauro Icardi
- Antoine Griezmann
Skąd strzelają bramki ci panowie?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
data %>% filter(player %in% top_strikers) %>% filter(result == "Goal") %>% ggplot() + geom_point(aes(x_coordinate, y_coordinate, color = player), show.legend = FALSE) + facet_wrap(~player) + # boisko xlim(c(0, 1)) + ylim(c(0, 1)) + geom_rect(aes(xmin = 0, ymin = 0, xmax = 1, ymax = 1), fill = NA, color = "black") + geom_rect(aes(xmin = 0, ymin = 0, xmax = 0.5, ymax = 1), fill = NA, color = "black") + geom_rect(aes(xmin = 0, ymin = 0.2, xmax = 0.157, ymax = 0.8), fill = NA, color = "black") + geom_rect(aes(xmin = 1, ymin = 0.2, xmax = 1-0.157, ymax = 0.8), fill = NA, color = "black") + labs(title = "Skąd padają bramki strzelone przez...", x = "", y = "") + theme_void() |
Tutaj jest jedna ciekawostka – Messi strzelający gola z prawego dolnego rogu boiska. Możemy poszukać tej bramki:
1 2 3 4 5 6 7 |
data %>% filter(player == "Lionel Messi", result == "Goal") %>% filter(y_coordinate == min(y_coordinate)) %>% t() %>% as.data.frame() %>% rownames_to_column() %>% set_names(c("Feature", "Value")) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
Feature | Value |
---|---|
match_id | 3926 |
league | La_Liga |
date | 2017-02-04 15:15:00 |
home | Barcelona |
away | Athletic Club |
home_goals | 3 |
away_goals | 0 |
team | Barcelona |
minute | 39 |
player | Lionel Messi |
x_g | 0.05206308 |
shot_type | LeftFoot |
result | Goal |
x_coordinate | 0.952 |
y_coordinate | 0.116 |
situation | DirectFreekick |
assist_player | NA |
preceding_action | Standard |
Chwila w Google z wyszukaniem odpowiedniego meczu i mamy wynik jak poniżej:
A z jakiej odległości padają strzały? Nie będziemy tego przeliczać na metry, a na jednostki względne od środka bramki (punkt (1,0.5) w układzie współrzędnych boiska):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
data %>% filter(player %in% top_strikers) %>% filter(result == "Goal") %>% mutate(distance = sqrt((x_coordinate-1)^2 + (y_coordinate-0.5)^2)) %>% group_by(player) %>% mutate(m_dist = mean(distance)) %>% ungroup() %>% arrange(m_dist) %>% mutate(player = fct_inorder(player)) %>% ggplot() + geom_boxplot(aes(player, distance, fill = player), color = "black", show.legend = FALSE) + coord_flip() + labs(title = "Z jakiej odległości od bramki padają gole?", x = "", y = "Odległośc [skala względna]") |
Wykres ułożono jest według średniej odległości, a kreska w pudełku mówi o medianie. Wcześniej widzieliśmy, że wszyscy strzelają głównie z pola karnego, zatem nic dziwnego że wyniki są zbliżone.
Poszukajmy najdalszego strzału:
1 2 3 4 5 6 7 8 |
data %>% filter(result == "Goal") %>% mutate(distance = sqrt((x_coordinate-1)^2 + (y_coordinate-0.5)^2)) %>% filter(distance == max(distance)) %>% t() %>% as.data.frame() %>% rownames_to_column() %>% set_names(c("Feature", "Value")) %>% kable() %>% kable_styling(bootstrap_options = c("striped", "hover", "condensed")) |
Feature | Value |
---|---|
match_id | 5424 |
league | Bundesliga |
date | 2014-09-20 14:30:00 |
home | Paderborn |
away | Hannover 96 |
home_goals | 2 |
away_goals | 0 |
team | Paderborn |
minute | 92 |
player | Moritz Stoppelkamp |
x_g | 0.008978859 |
shot_type | RightFoot |
result | Goal |
x_coordinate | 0.225 |
y_coordinate | 0.475 |
situation | OpenPlay |
assist_player | Uwe H�nemeier |
preceding_action | None |
distance | 0.7754031 |
Znowu chwila z Google i mamy:
Jak wygląda rozkład wyników w poszczególnych ligach? Jaki wynik meczu jest najpopularniejszy? Poniższy wykres to obrazuje:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
data %>% select(league, home_goals, away_goals, match_id) %>% distinct(match_id, .keep_all = TRUE) %>% count(league, away_goals, home_goals, sort = T) %>% group_by(league) %>% mutate(p = 100*n/sum(n)) %>% ungroup() %>% ggplot() + geom_tile(aes(home_goals, away_goals, fill = p), color = "black", show.legend = FALSE) + geom_text(aes(home_goals, away_goals, label = sprintf("%.f%%", p))) + scale_x_continuous(breaks = 0:10, limits = c(-1,11)) + scale_y_continuous(breaks = 0:10, limits = c(-1,11)) + scale_fill_distiller(palette = "Reds", direction = 1) + labs(title = "Rozkład wyników w meczach", x = "Gospodarze", y = "Goście") + facet_wrap(~league) |
Najpopularniejsze wyniki to 1:1 albo 1:0 (czy też 0:1). Zdaje się, że rozkład liczby bramek w meczu to rozkład Poissona – to warto wiedzie, jeśli się chce budować jakieś modele przewidujące wyniki.
Przejdźmy na poziom dwóch drużyn. Na początek policzymy sobie dane mówiące o rozkładzie wyników spotkań wszystkich drużyn z każdej ligi pomiędzy sobą:
1 2 3 4 5 6 7 8 9 10 11 |
data_pairs <- data %>% select(home, away, league, home_goals, away_goals, match_id) %>% distinct(match_id, .keep_all = TRUE) %>% mutate(hG = if_else(home < away, home_goals, away_goals), aG = if_else(home < away, away_goals, home_goals), h = if_else(home < away, home, away), a = if_else(home < away, away, home)) %>% count(h, hG, a, aG) %>% group_by(h, a) %>% mutate(p = 100*n/sum(n)) %>% ungroup() |
Teraz wybierzemy dwie drużyny i zobaczymy jakie wyniki padły w meczach między nimi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
A_team = "Manchester City" B_team = "Liverpool" data_sel <- data_pairs %>% filter(h %in% c(A_team, B_team), a %in% c(A_team, B_team)) home_team <- data_sel %>% pull(h) %>% unique() away_team <- data_sel %>% pull(a) %>% unique() data_sel %>% ggplot() + geom_tile(aes(hG, aG, fill = p), color = "black", show.legend = FALSE) + geom_text(aes(hG, aG, label = sprintf("%.f%%", p))) + scale_x_continuous(breaks = 0:10, limits = c(-1,11)) + scale_y_continuous(breaks = 0:10, limits = c(-1,11)) + scale_fill_distiller(palette = "Reds", direction = 1) + labs(title = paste("Rozkład wyników w meczach\n", home_team, "-", away_team), x = home_team, y = away_team) |
Niestety nie ma bardziej zróżnicowanych danych – Real z Barcą wygląda podobnie (każdy z wyników padł tylko jeden raz, meczy też było 10). Szkoda.
Ale możemy inaczej – ile bramek strzela i ile traci Barcelona w lidze hiszpańskiej?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
sel_team = "Barcelona" # bilans rozgrywek data_pairs %>% filter(h == sel_team | a == sel_team) %>% mutate(sel_goals = if_else(h == sel_team, hG, aG), other_goals = if_else(h == sel_team, aG, hG), other = if_else(h == sel_team, a, h)) %>% select(other, sel_goals, other_goals, n) %>% gather("key", "val", -other, -n) %>% mutate(key = factor(key, levels = c("sel_goals", "other_goals"), labels = c("Bramki strzelone", "Bramki stracone"))) %>% ggplot() + geom_tile(aes(other, val, fill = n), color = "black") + scale_y_continuous(breaks = 0:10) + scale_fill_distiller(palette = "Reds", direction = 1) + facet_wrap(~key, ncol = 2) + theme(axis.text.x = element_text(angle = 90, vjust = 0, hjust = 1)) + labs(title = paste0("Liczba strzelonych/straconych bramek: ", sel_team), x = "Przeciwnik", y = "", fill = "Liczba bramek") |
Oczywiście zamiast Barcelony możemy wybrać inny zespół.
A jak wygląda bilans bramek Barcy? Ile średnio goli strzela i ile traci w meczach ze swoimi rywalami z La Liga?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
data_pairs %>% filter(h == sel_team | a == sel_team) %>% mutate(sel_goals = if_else(h == sel_team, hG, aG), other_goals = if_else(h == sel_team, aG, hG), other = if_else(h == sel_team, a, h)) %>% select(other, sel_goals, other_goals, n) %>% mutate(sel_goals = n * sel_goals, other_goals = n * other_goals) %>% group_by(other) %>% summarise(sel_goals = sum(sel_goals)/n(), other_goals = sum(other_goals)/n()) %>% ungroup() %>% mutate(delta = sel_goals - other_goals) %>% arrange(desc(delta)) %>% mutate(other = fct_inorder(other) %>% fct_rev()) %>% ggplot() + geom_col(aes(other, sel_goals), fill = "green") + geom_text(aes(other, sel_goals, label = sprintf("%.2f", sel_goals)), hjust = -0.1) + geom_col(aes(other, -other_goals), fill = "red") + geom_text(aes(other, -other_goals, label = sprintf("%.2f", other_goals)), hjust = 1.01) + geom_point(aes(other, delta), color = "black", size = 2) + # geom_text(aes(other, delta, label = sprintf("%.2f", delta)), hjust = -0.2) + coord_flip() + labs(title = paste0("Średnia liczba bramek strzelonych/straconych: ", sel_team), subtitle = "Zielony = bramki strzelone\nCzerwony = bramki stracone", x = "Przeciwnik", y = "") |
Czarna kropka to różnica średnich – jak widać FC Barcelona z każdym rywalem jest na plusie.
Wróćmy do naszych top 12 zawodników. Kto im asystuje? Możemy narysować to na grafie:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
passes_graph <- data %>% filter(result == "Goal") %>% filter(player %in% top_strikers) %>% filter(!is.na(assist_player)) %>% count(assist_player, player) %>% select(from = assist_player, to = player, weight = n) %>% graph_from_data_frame(directed = TRUE) plot(passes_graph, vertex.color = if_else(V(passes_graph)$name %in% top_strikers, "blue", "lightblue"), vertex.size = if_else(V(passes_graph)$name %in% top_strikers, 7, 3), vertex.label.cex = 1, vertex.label.color = if_else(V(passes_graph)$name %in% top_strikers, "gray80", "gray20"), edge.arrow.size = 0, edge.arrow.width = E(passes_graph)$weight, edge.width = E(passes_graph)$weight, edge.curved = TRUE) |
Nie widać tego dobrze na powyższym obrazku, ale w odpowiednim powiększeniu (kliknij na obrazek) widać na przykład pana Lucasa Mourę – jest pomiędzy dwoma różnymi grupami. Dlaczego? Ano, bo przeszedł z PSG do Tottenham i podaje już komuś innemu :)
Przy użyciu pakietu networkD3 możemy przygotować z gotowego grafu (obiektu pakietu igraph) interaktywną wersję:
1 2 3 4 5 6 7 8 9 10 11 |
library(networkD3) passes_graph_d3 <- igraph_to_networkD3(passes_graph) forceNetwork(Links = passes_graph_d3$links, Nodes = passes_graph_d3$nodes, Source = 'source', Target = 'target', NodeID = 'name', Group = 'name', linkWidth = passes_graph_d3$links$value, fontSize = 11, opacityNoHover = 0.6, zoom = TRUE) |
Prawda, że fajne?
To początek prac, jakieś pomysły po pół dnia przyglądania się danym. Jeśli masz ochotę – możesz użyć przygotowanego wyżej kodu do zbudowania na przykład aplikacji w Shiny, w której będzie można wybrać drużyny albo zawodników i dla każdego takiego wyboru wygenerować odpowiednie wykresiki. A gdyby jeszcze zasilać dane (trzeba by scrapper napisać) każdego dnia byłoby prawie online. Dlaczego understat.com tego nie ma?
Miło będzie jeśli docenisz trud autora stawiając dużą kawę. Wpadnij też na Dane i Analizy na Facebooku – tam więcej takich smaczków (szczególnie dla praktyków).
Hej,
Źle podlinkowany plik /downloads_02-1.png (zapewne histogram). Poprawisz? :)
Pozdrawiam
Mariusz
Już powinno być ok
Działa :) Fajna analiza, bardzo inspirująca :)
Hey, the dataset from Reddit has been deleted. Can you please send me the dataset?
a czy nie jest tak, że 45 i często 46 a nawet 47 minuta jest policzona *podwójnie* przy statystykach goli? (jako pierwsza i druga połowa)
i dlatego wydaje się, że statystycznie wtedy pada więcej bramek w porównaniu do innych przedziałów?
Tego nie wiem i mam podobne podejrzenie. Z drugiej strony to byłoby jednak bez sensu…
Dzień dobry,
czy można prosić o wrzucenie ponownie bazy danych na Google Drive. Aktualny link nie działa.
Pozdrawiam,
Paweł Sobala
Wrzuciłem zzipowanego CSV.
Dziękuję!
Super rozpisane i bardzo ciekawe, pozdrawiam :-)