Ismael Gómez Schmidt
Data Scientist 49ing.ch / Co-Founder futbolytics.cl / Frontman datofutbol.cl
Registro de distintos eventos relevantes con sus detalles respectivos
Registro de coordenadas para los 22 jugadores y el balón
devtools::install_github("statsbomb/StatsBombR")
library(StatsBombR)
competitions <- FreeCompetitions()
liga_spain <- competitions %>% filter(competition_id == 11)
range(liga_spain$season_name)
games <- FreeMatches(liga_spain)
glimpse(games)
unique(paste0(games$home_team.home_team_name, "-",
games$away_team.away_team_name))
barcelona_games <- games %>%
filter("Barcelona" %in% c(home_team.home_team_name,
away_team.away_team_name))
barcelona_events <- StatsBombFreeEvents(MatchesDF = barcelona_games)
library(readr)
#write_rds(barcelona_events, "barcelona_events.rds")
#barcelona_events <- read_rds("barcelona_events.rds")
messi_events <- barcelona_events %>%
filter(str_detect(player.name, "Messi"))
glimpse(messi_events)
table(messi_events$type.name)
messi_shots <- messi_events %>%
filter(type.name == "Shot")
messi_shots_cleaned <- allclean(messi_shots)
data <- messi_shots_cleaned %>%
left_join(liga_spain %>% select(season_id, season_name)) %>%
select(match_id, period, timestamp, type.name, possession_team.name, play_pattern.name,
player.name, position.name, shot.type.name, location.x, location.y,
shot.body_part.name, shot.technique.name, shot.statsbomb_xg,
shot.outcome.name, shot.end_location.x, shot.end_location.y, season_name)
devtools::install_github("boxuancui/DataExplorer")
library(DataExplorer)
plot_bar(data %>% select(shot.type.name, shot.outcome.name), ncol = 2)
plot_density(data %>% select(location.x, location.y), ncol = 1)
Paquetes: {dplyr}{tidyr}{lubridate}{forcats}{ggplot2}{DataExplorer}
Coordenadas según proveedor
data <- data %>%
mutate_at(vars(contains('.x')), funs( . / 120 * 110)) %>%
mutate_at(vars(contains('.y')), funs( (80 - .) / 80 * 73))
data_free_kick <- data %>%
filter(shot.type.name == "Free Kick")
library(jpeg)
img <- jpeg::readJPEG("image_path")
library(grid)
p <- rasterGrob(img, width = unit(1, "npc"), height = unit(1, "npc"))
library(ggplot2)
g <- ggplot() +
annotation_custom(p, xmin = -0.5, xmax = 110.5,
ymin = -0.5, ymax = 73.5) +
scale_x_continuous(limits = c(-0.5, 110.5), expand = c(0,0)) +
scale_y_continuous(limits = c(-0.5, 73.5), expand = c(0,0))
g + geom_point(data = data_free_kick,
mapping = aes(x = location.x, y = location.y),
pch = 21, alpha = 0.2, fill = "red", size = 2)
library(png)
img2 <- png::readPNG("image2_path")
p2 <- rasterGrob(img2, width = unit(1, "npc"), height = unit(1, "npc"))
g2 <- ggplot() +
annotation_custom(p2, xmin = - Inf, xmax = Inf, ymin = - Inf, ymax = Inf) +
scale_x_continuous(limits = c(-15, 15), expand = c(0,0)) +
scale_y_continuous(limits = c(7, 30.2), expand = c(0,0))
g2
library(ggforce)
# función para dibujar la mitad ofensiva de la cancha invertida
get_pitch <- function(gp, pitch_fill = "white", pitch_col = "lightgrey"){
contorno_df <- data.frame(x = c(55, 55, 110, 110),
xend = c(55, 110, 110, 55),
y = c(0, 73, 73, 0),
yend = c(73, 73, 0, 0))
areas_df <- data.frame(x = c(110, 93, 93, 110, 104, 104),
xend = c(93, 93, 110, 104, 104, 110),
y = c(16, 16, 57, 27, 27, 46),
yend = c(16, 57, 57, 27, 46, 46))
gp +
theme_void() +
theme(panel.background = element_rect(fill = pitch_fill),
plot.margin = unit(c(0.3, 0.3, 0.3, 0.3), "cm")) +
# rectángulos
geom_segment(data = contorno_df,
aes(x = x, xend = xend, y = y, yend = yend),
col = pitch_col) +
geom_segment(data = areas_df,
aes(x = x, xend = xend, y = y, yend = yend),
col = pitch_col) +
geom_rect(aes(xmin = 110, xmax = 111.5, ymin = 33, ymax = 40),
fill = "transparent", col = pitch_col) +
# puntos
geom_point(aes(x = 110/2, y = 73/2), col = pitch_col) +
geom_point(aes(x = 98, y = 73/2), col = pitch_col) +
# semi círculos
geom_arc(aes(x0 = 98, y0 = 73/2, r = 9.15, start = -34*pi/180,
end = -146*pi/180), col = pitch_col) + #sigue...
}
geom_arc(aes(x0 = 110/2, y0 = 73/2, r = 9.15, start = 0,
end = 180*pi/180), col = pitch_col) +
geom_arc(aes(x0 = 110, y0 = 73, r = 1, start = 270*pi/180,
end = 360*pi/180), col = pitch_col) +
geom_arc(aes(x0 = 110, y0 = 0, r = 1, start = 180*pi/180,
end = 270*pi/180), col = pitch_col) +
coord_flip() +
scale_y_reverse()
}
get_pitch(gp = ggplot(),
pitch_fill = "white", pitch_col = "black") +
geom_point(data = data_free_kick,
mapping = aes(x = location.x, y = location.y),
alpha = 0.3, col = "darkblue", size = 2)
data_free_kick <- data_free_kick %>%
mutate(is_goal = ifelse(shot.outcome.name == "Goal", "GOAL", "NO GOAL"))
get_pitch(gp = ggplot(data_free_kick), pitch_fill = "white", pitch_col = "black") +
geom_point(mapping = aes(x = location.x, y = location.y, size = shot.statsbomb_xg, fill = is_goal), pch = 21, alpha = 0.3, col = "black", stroke = 1.05) +
scale_fill_brewer(palette = "Set1") +
theme(legend.position = "top")
n_games <- data %>% distinct(match_id) %>% nrow()
messi_stats <- data_free_kick %>%
summarise(Games = n_games, Shots = n(), xG_Sum = round(sum(shot.statsbomb_xg), 2),
Goals = sum(ifelse(is_goal == "GOAL", 1, 0)),
xG_dif = paste(ifelse(Goals > xG_Sum, "+", ""), round(Goals - xG_Sum, 2)),
xG_per_shot = round(xG_Sum / Shots, 2), Shots_per_goal = round(Shots/Goals, 2)) %>%
t() %>% as.data.frame()
library(gridExtra)
tt <- ttheme_minimal(base_size = 8, core = list(bg_params = list(fill = NA, col = NA),
fg_params = list(fontface = 3L, col = "white")),
rowhead = list(fg_params = list(col = "white", fontface = 3L)))
library(ggtext)
g <- ggplot(data_free_kick) +
geom_density2d_filled(mapping = aes(x = location.x, y = location.y, fill = ..level..),
contour_var = "ndensity", breaks = seq(0.1, 1.0, length.out = 10)) +
scale_fill_brewer(palette = "YlOrRd", direction = -1) +
geom_point(data = data_free_kick %>% filter(shot.outcome.name == "Goal"),
mapping = aes(x = location.x, y = location.y, size = shot.statsbomb_xg), fill = "blue",
pch = 21, alpha = 0.5, col = "white", stroke = 1)
get_pitch(gp = g, pitch_fill = "black") +
guides(fill = "none", size = guide_legend(title = "xG")) +
theme(legend.position = "top",
plot.title = element_text(size = 16, hjust = 0.5),
plot.subtitle = element_markdown(size = 12, hjust = 0.5)) +
annotation_custom(tableGrob(messi_stats, cols = NULL, theme = tt,
rows = c("Partidos", "Tiros libres", "suma xG", "Goles",
"xG dif.", "xG por shot", "Tiros por gol")),
xmin = 65, xmax = 70, ymin = -8, ymax = -8) +
labs(title = "Tiros libres de Messi en La Liga 2006/2007 - 2019/2020",
subtitle = "Mapa de calor indica densidad de tiros. Puntos indican <span style='color:blue'>**Goles**</span>.<br/ >",
caption = "Autor: @DatoFutbol_cl | Data: Statsbomb")