Machine Learning não é só para prever doenças ou recomendar filmes. No futebol, ele pode identificar padrões táticos que o olho humano levaria horas para mapear — e que muitos analistas simplesmente ignoram por não terem as ferramentas certas.
Neste artigo você vai ver como aplicar ML em R para estudar regiões de recuperação de bola, altura de bloco e intensidade de pressão usando um dataset real da Liga Argentina. O processo completo — da engenharia de variáveis à interpretação dos clusters.
A maioria dos analistas assiste às partidas para identificar padrões. O problema é que assistir a 30 jogos para entender o comportamento defensivo de um time é inviável em uma rotina de clube.
Com dados e Machine Learning, você processa esses 30 jogos em minutos. E mais importante: você encontra padrões que não seriam visíveis assistindo — porque envolvem a combinação de múltiplas variáveis ao mesmo tempo.
A pergunta central que vamos responder: quais times realmente jogam com bloco alto, e quais apenas parecem que jogam?
Antes do código, é importante entender o que estamos modelando. Após o processo de clusterização com ML, os times se dividem em três grupos táticos principais:
Cumprem os três critérios simultaneamente: recuperam a bola longe do próprio gol, têm alto volume de ações defensivas por minuto e foram classificados pelo algoritmo no cluster de topo. São os times que jogam com bloco alto de forma consistente e eficiente.
Recuperam a bola em zonas avançadas e têm alta pressão, mas o bloco como unidade está descompacto. Mordem muito, porém de forma desordenada. O ML não os classifica no topo porque outros indicadores — como distância entre linhas — os penalizam.
Têm alta intensidade de pressão, mas não conseguem recuperar a bola no alto. O esforço existe — o time sobe a linha, tenta pressionar — mas o adversário quebra a pressão com facilidade. É o famoso esforço sem eficiência tática.
O primeiro passo é transformar os eventos individuais de cada partida em métricas por time. Vamos focar em três variáveis principais: altura média das recuperações, volume de pressões por minuto e interceptações no terço ofensivo.
library(tidyverse)
library(tidymodels)
# Supondo que você tem um dataset de eventos com as colunas:
# team, minute, type, x, y (coordenadas do campo 0-100)
metricas_time <- eventos %>%
group_by(team, match_id) %>%
summarise(
# Altura média das recuperações (y > 67 = terço ofensivo)
recuperacoes_altas = sum(type == "Ball Recovery" & y > 67, na.rm = TRUE),
altura_media_recuperacao = mean(y[type == "Ball Recovery"], na.rm = TRUE),
# Volume de pressões por minuto de jogo
pressoes_por_min = sum(type == "Pressure", na.rm = TRUE) / max(minute),
# Interceptações no terço ofensivo
interceptacoes_alto = sum(type == "Interception" & y > 67, na.rm = TRUE)
) %>%
ungroup()
# Normalizar as variáveis (essencial para K-Means)
metricas_scaled <- metricas_time %>%
select(recuperacoes_altas, altura_media_recuperacao,
pressoes_por_min, interceptacoes_alto) %>%
scale() %>%
as_tibble()
# Definir número de clusters (3 grupos táticos)
set.seed(42)
modelo_kmeans <- kmeans(metricas_scaled, centers = 3, nstart = 25)
# Adicionar cluster ao dataset original
metricas_time <- metricas_time %>%
mutate(cluster = as.factor(modelo_kmeans$cluster))
library(ggplot2)
# Gráfico de dispersão: pressão vs altura de recuperação
ggplot(metricas_time,
aes(x = pressoes_por_min,
y = altura_media_recuperacao,
color = cluster,
label = team)) +
geom_point(size = 4, alpha = 0.8) +
geom_text(hjust = -0.1, size = 3, color = "black") +
scale_color_manual(
values = c("#1d4a2e", "#5ecf82", "#e8e2d8"),
labels = c("Elite tática", "Pressão desordenada", "Bloco baixo")
) +
labs(
title = "Clusters táticos por intensidade de pressão e altura de bloco",
x = "Pressões por minuto",
y = "Altura média de recuperação (0-100)",
color = "Perfil tático"
) +
theme_minimal() +
theme(plot.title = element_text(face = "bold"))
Para entender quais times cumprem múltiplos critérios simultaneamente:
library(ggVennDiagram)
# Definir os grupos por critério
bloco_alto_ml <- metricas_time %>%
filter(cluster == 1) %>% pull(team)
recuperacao_alta <- metricas_time %>%
filter(altura_media_recuperacao > quantile(altura_media_recuperacao, 0.67)) %>%
pull(team)
pressao_intensa <- metricas_time %>%
filter(pressoes_por_min > quantile(pressoes_por_min, 0.67)) %>%
pull(team)
# Plotar diagrama
ggVennDiagram(list(
"Bloco Alto (ML)" = bloco_alto_ml,
"Recuperação Alta" = recuperacao_alta,
"Pressão Intensa" = pressao_intensa
))
Após rodar o modelo na Liga Argentina, os padrões encontrados foram:
33% dos times se enquadram como elite tática — cumprem os três critérios. São os times que jogam com bloco alto de verdade, com consistência e eficiência.
33% têm pressão e recuperação alta, mas o ML não os classifica no topo. São os “estrategistas sem intensidade” — jogam alto, mas de forma desordenada.
17% têm alta intensidade de pressão mas não recuperam a bola no alto. O esforço existe, a eficiência não. Correm muito no lugar errado.
O dado mais revelador: 0% dos times foram classificados pelo ML como bloco alto sem também terem recuperações altas na prática. Isso mostra que o modelo é consistente — ele não rotula um time de bloco alto se os dados não comprovam isso em campo.
Um técnico pode acreditar que seu time joga com bloco alto. Os dados podem mostrar o contrário. Essa diferença entre percepção e realidade é exatamente onde o analista de dados gera valor — quando ele tem coragem e ferramentas para mostrar o que está acontecendo de fato.
Não basta assistir ao jogo. É preciso medir.
O curso Estatística Computacional no Futebol do Campo Analítico cobre Machine Learning aplicado ao futebol — clusterização, Random Forest, séries temporais e muito mais — com dados reais e código R completo disponível no GitHub.
Publicado por Aldrei · Campo Analítico — Dados & Futebol
Aprenda do zero ao avançado com o método Campo Analítico. Garanta sua vaga!
Quero me inscrever agoraAssine para receber nossas notícias mais recentes por e-mail.