Introdução
“Atleta do século”, “Rei do futebol”: são muitos os epítetos atribuídos àquele que é considerado o maior jogador de futebol de todos os tempos - Edson Arantes do Nascimento, Pelé.
Os números de Pelé são grandiosos e eloquentes, mas não são incontroversos. Tema da historiografia do futebol, o debate permanece vivo na crônica esportiva.
Apesar da magia dos acontecimentos, não há consenso sobre a contagem de gols do astro tricordiano. É o que diz a página de resultados, no topo, quando perguntamos ao Google quantos gols Pelé fez na carreira.
Longe da polêmica, fazemos uso de um verbete da enciclopédia livre Wikipédia, que pretende ser um compilado acerca das estatísticas disponíveis sobre os jogos disputados e os gols marcados por Pelé, de onde extraímos as tabelas empregadas para análise exploratória, com o uso do R - linguagem de programação e ambiente de desenvolvimento integrado para cálculos estatísticos e visualização gráfica.
Objetivo
Análise exploratória de dataset, criado a partir da junção de tabelas disponibilizadas publicamente em artigo publicado na Wikipédia, com uso do R - ferramenta largamente utilizada na ciência de dados.
Recursos
Listagem de jogos e gols disponíveis em: https://pt.wikipedia.org/wiki/Estat%C3%ADsticas_de_Pel%C3%A9.
Último acesso em: 09/05/2023.
Bibliotecas
Carregamos as seguintes bibilotecas do R, para adicionar funcionalidades extras:
- rvest - biblioteca para extração de dados web;
- data.table - pacote que contém a função rbindlist;
- stringr - ferramenta para manipulação de textos;
- tidyverse - pacote para manipulação de dados;
- lubridate - biblioteca para manipular dados no formato data/hora;
- ggplot2 - ferramenta para visualização de dados;
- rmdformats - temas adicionais para documentos Rmarkdown;
- DT - para incluir tabelas em relatórios Rmarkdown.
Diretório de trabalho
Definimos o diretório de trabalho:
setwd("/home/gf/Scripts/Pele")
Coleta de dados
Acessamos a página web
url <- "https://pt.wikipedia.org/wiki/Estatísticas_de_Pelé"
page <- read_html(url)
texto <- page %>%
html_text() %>%
str_split(pattern = "\n") %>%
unlist() %>%
str_trim()
Inspecionamos quantas tabelas há na página
tbls <- html_nodes(page, "table")
length(tbls)
## [1] 27
Listamos as tabelas existentes
head(tbls)
## {xml_nodeset (6)}
## [1] <table class="wikitable plainrowheaders sortable" style="font-size:90%">< ...
## [2] <table class="wikitable plainrowheaders sortable" style="font-size:90%">< ...
## [3] <table class="wikitable plainrowheaders sortable" style="font-size:90%">< ...
## [4] <table class="wikitable plainrowheaders sortable" style="font-size:90%">< ...
## [5] <table class="wikitable plainrowheaders sortable" style="font-size:90%">< ...
## [6] <table class="wikitable" style="text-align:center"><tbody>\n<tr>\n<th row ...
Identificação das tabelas
Notamos que, no cabeçalho, após a tag “table”, foram adicionados à classe os atributos “wikitable” e “sortable”, que permite que as colunas sejam ordenadas; como sabemos que os objetos table são numerados por ordem de aparição na página, presumimos que as cinco primeiras tabelas contenham o conteúdo desejado.
Baixamos as cinco primeiras tabelas
tbls <- page %>%
html_nodes("table") %>%
.[1:5] %>%
html_table(fill = TRUE)
Unificamos as tabelas
df <- as_tibble(rbindlist(tbls))
Inspecionamos o novo objeto criado
glimpse(df)
## Rows: 1,394
## Columns: 7
## $ Data <chr> "1956-09-077 de setembro de 1956", "1956-11-1515 de novembr…
## $ Equipe <chr> "Santos", "Santos", "Santos", "Santos", "Santos", "Santos",…
## $ Placar <chr> "7–1", "4–2", "1–0", "2–4", "5–0", "3–1", "2–3", "5–0", "5–…
## $ Adversário <chr> "Corinthians FC", "Jabaquara", "AIK", "Portuguesa", "Améric…
## $ Local <chr> "Américo Guazelli, Santo André", "Vila Belmiro, Santos", "V…
## $ Competição <chr> "Amistoso", "Amistoso", "Amistoso", "Amistoso", "Amistoso",…
## $ Gols <chr> "1", "1", "0", "0[gol 1]", "0", "1", "0", "0", "0", "0", "0…
Limpeza e preparação dos dados
Verificação de discrepância
Primeiro, verificamos se há discrepância entre o número de jogos
listados no dataset e a quantidade mencionada no artigo
publicado na Wikipédia.
Para isso, utilizamos uma função
que retorna o texto contido em um critério de busca.
total <- grep('[0-9]+ jogos e [0-9]+ gols', unlist(strsplit(texto,'(?<=[?!.])\\s',
perl=TRUE)), value=TRUE)
total
## [1] "A lista do presente artigo contabilizou um total de 1373 jogos e 1287 gols."
Detecção de missing values
Há uma diferença de 21 partidas entre a informação do artigo e o número de linhas do dataset:
mv <- subset(df, !complete.cases(df))
mv
## # A tibble: 21 × 7
## Data Equipe Placar Adversário Local Competição Gols
## <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 2 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 3 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 4 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 5 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 6 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 7 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 8 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 9 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## 10 <NA> Santos <NA> <NA> <NA> <NA> <NA>
## # ℹ 11 more rows
Remoção de referências
Removemos as referências contidas no corpo do artigo, que estão inseridas entre colchetes []:
df <-as_tibble(apply(df,2,
function(x) str_replace_all(string=x,
pattern="\\s*\\[[^\\]]+\\]" , repl="")))
Formatação de data
Extraímos o campo Data no formato yyyy-mm-dd:
df$Data <- str_extract( df$Data, "\\d{4}-\\d{2}-\\d{2}")
Definição do tipo de dados
Definimos o campo Gol como integer e o campo Data como date:
df$Gols <- as.integer(df$Gols)
df$Data <- as.Date(df$Data)
Remoção de missing values
df <- df %>% na.omit()
Remoção de caracteres residuais
df$Local <- str_trim(gsub(",", "", df$Local))
Contagem das linhas
A seguir, contamos quantas linhas compõem o dataset:
nrow(df)
## [1] 1373
Prova dos nove
Sabemos de antemão que, se foram jogadas 1373 partidas, deveria haver igual quantidade de datas distintas no campo Data do dataset. Logo, a função a seguir, fornece, para cada campo, a quantidade de elementos distintos.
sapply(df, function(x) n_distinct(x))
## Data Equipe Placar Adversário Local Competição Gols
## 1369 15 66 391 340 106 7
Partidas dobradas?
Se o dataset contém 1373 linhas, mas há apenas 1369 datas, teria Pelé jogado mais de uma partida em um mesmo dia? O filtro abaixo vai exibir as partidas que teriam sido disputadas no mesmo data.
df %>% group_by(Data) %>% filter(n()>1)
## # A tibble: 8 × 7
## # Groups: Data [4]
## Data Equipe Placar Adversário Local Competição Gols
## <date> <chr> <chr> <chr> <chr> <chr> <int>
## 1 1959-05-26 Santos 1–0 Standard de Liège Sclessin Liège Bé… Amistoso 0
## 2 1959-05-26 Santos 4–2 Anderlecht Émile Versé Bruxe… Amistoso 2
## 3 1959-08-23 Santos 4–3 Noroeste Antônio Garcia Ba… Campeonat… 3
## 4 1959-08-23 Santos 3–2 Corinthians Pacaembu São Paulo Campeonat… 1
## 5 1959-12-10 Santos 2–3 Bahia Vila Belmiro Sant… Campeonat… 1
## 6 1959-12-10 Santos 2–0 Bahia Fonte Nova Salvad… Campeonat… 1
## 7 1961-12-16 Santos 4–1 São Paulo Vila Belmiro Sant… Campeonat… 1
## 8 1961-12-16 SAPESP 4–1 SAFERJ Pacaembu São Paulo Amistoso 1
Correção das datas
Corrigimos as datas com base nas informações obtidas nos sites:
acervosantosfc.com
sindicatodeatletas.com.br/historia/a-historia/
df$Data[df$Data == '1959-05-26' & df$Adversário == 'Anderlecht'] <- '1959-05-27'
df$Data[df$Data == '1959-08-23' & df$Adversário == 'Corinthians'] <- '1959-08-26'
df$Data[df$Data == '1959-12-10' & df$Local == 'Fonte Nova Salvador'] <- '1959-12-30'
df$Data[df$Data == '1961-12-16' & df$Adversário == 'SAFERJ'] <- '1961-12-19'
Análise exploratória
Novo tira-teima
Verificamos novamente quantos elementos distintos há em cada campo:
sapply(df, function(x) n_distinct(x))
## Data Equipe Placar Adversário Local Competição Gols
## 1373 15 66 391 340 106 7
Esta função fornece algumas informações interessantes: por exemplo,
Pelé teria participado, em 1373
partidas, de 106 competições, atuado por
15 equipes diferentes, contra 391
adversários, que terminaram com 66 placares distintos,
e que a quantidade de gols marcados pelo craque pode ser agrupada em
7 categorias.
Mas, se observamos atentamente o
datatable a seguir, notamos que a descrição de algumas
competições contém data depois do nome, informação indispensável, pois
algumas competições foram finalizadas somente no ano seguinte.
datatable(df, list(iDisplayLength = 5))
Desse modo, para calcular exatamente de quantas competições distintas Pelé teria participado, vamos remover a string “de [ano]”, do campo Competição, com o uso da função str_remove:
df1 <- df
df1$Competição <- str_trim(str_remove(df1$Competição, pattern = "de \\d{4}(.*)"))
datatable(df1, list(iDisplayLength = 5))
Rodamos novamente a função n_distinct, que serve tanto para inspecionar os dados como para fornecer o insigth inicial. Constatamos que o número de competições foi reduzido para 50.
sapply(df1, function(x) n_distinct(x))
## Data Equipe Placar Adversário Local Competição Gols
## 1373 15 66 391 340 50 7
Se os gols marcados por Pelé podem ser agrupados em sete categorias, que representam quantidades distintas, inclusive “nenhum ou zero”, quais são elas?
sort(unique(df1$Gols))
## [1] 0 1 2 3 4 5 8
Funções: ferramentas reutilizáveis
Para que evitemos reescrever o código repetidamente, vamos criar duas
funções para agrupamento de dados.
Depois de prontas, basta
chamá-las e passar os argumentos, para obtermos o resultado
esperado.
Passamos como argumento o nome da coluna a ser agrupada e
o nome da coluna a ser ordenada. Na primeira função, reformulamos o
dataset, por isso referimos a coluna Gols com
minúscula(gols)
lembre-se disso ao passar o argumento. A
diferença entre elas é que a segunda exibe como saída a proporção e a
primeira a soma.
agrupar1 <- function(df1, grp, arr ) {
df1 %>%
group_by({{grp}}) %>%
reframe(partidas = length(Data), gols = sum(Gols)) %>%
arrange(desc({{arr}}))
}
agrupar2 <- function(df1, grp, arr) {
df1 %>%
group_by({{grp}}) %>%
reframe(partidas = length(Data)) %>%
mutate(prop = (partidas / sum(partidas) * 100)) %>%
arrange(desc({{arr}}))
}
Então vejamos a representação cardinal e proporcional das partidas em
relação às sete categorias. Em mais da metade das partidas disputadas,
Pelé encontrou o caminho das redes. Em 3 de 10
partidas, estufou as redes com um gol e em 1 a cada 10 partidas fez 2
gols. Até hoje lidera o rankig de hat-tricks,
que é quando um jogador faz três gols em uma mesma partida, com 91 no
total. No entanto, os dados demonstram como o gol é um evento
excepcional em uma partida de futebol, pois em 40% delas o craque deixou
o gramado cabisbaixo, sem nenhum tento.
gp <- agrupar2(df1, Gols, Gols)
gp
## # A tibble: 7 × 3
## Gols partidas prop
## <int> <int> <dbl>
## 1 8 1 0.0728
## 2 5 7 0.510
## 3 4 30 2.18
## 4 3 91 6.63
## 5 2 191 13.9
## 6 1 469 34.2
## 7 0 584 42.5
ggplot(gp, aes(x = Gols, y = partidas)) +
geom_bar(stat = "identity") +
labs(title = "Quantidade de gols vs Quantidade de partidas", x = "Gols", y = "Partidas") +
theme_tufte() +
theme(panel.background = element_rect (fill = "white", colour = "black"))
Pelé atuou por diversas equipes, ao longo da sua carreira. Inserimos os parâmetros adequados na função agrupar, para calcular a quantidade de partidas e a quantidade de gols marcados em cada uma delas.
gpe <- agrupar1(df1, Equipe, gols)
gpe
## # A tibble: 15 × 3
## Equipe partidas gols
## <chr> <int> <int>
## 1 Santos 1114 1092
## 2 Brasil 112 94
## 3 NY Cosmos 107 66
## 4 6º GAC 6 10
## 5 Seleção Paulista 13 10
## 6 Comb. Santos/ Vasco da Gama 4 6
## 7 Seleção Militar Brasileira 5 4
## 8 SAPESP 2 3
## 9 Brasil (não oficial) 2 1
## 10 Comb. Brasil 1 1
## 11 All-Stars 2 0
## 12 Brasil de Seniores 1 0
## 13 Ex-NY Cosmos 1 0
## 14 Flamengo 1 0
## 15 Fluminense 2 0
ggpe <- ggplot(data = gpe %>% gather(Variáveis, partidas, -Equipe),
aes(x = reorder(Equipe, +partidas), y = partidas, fill = Variáveis)) +
geom_bar(stat = "identity", position = "dodge") +
theme_tufte()
ggpe + coord_flip() +
theme(axis.text.y = element_text(size=rel (1.2))) +
ylab("partidas/gols") +
xlab("")
Revelamos o desempenho do Rei em algumas competições de que participou.
gpc <- agrupar1(df1, Competição, gols)
gpc
## # A tibble: 50 × 3
## Competição partidas gols
## <chr> <int> <int>
## 1 Amistoso 511 481
## 2 Campeonato Paulista 410 466
## 3 Campeonato Brasileiro 174 101
## 4 Torneio Rio-São Paulo 53 49
## 5 North AmericanSoccer League 64 37
## 6 Copa Libertadores 15 16
## 7 Torneio Internacional do Chile 10 15
## 8 Copa do Mundo 14 12
## 9 Campeonato Sul-Americano 6 8
## 10 Copa Intercontinental 3 7
## # ℹ 40 more rows
gpc10 <- gpc %>%
arrange(desc(partidas)) %>%
slice(1:10)
ggpc <- ggplot(data = gpc10 %>% gather(Variáveis, partidas, -Competição),
aes(x = reorder(Competição, +partidas), y = partidas, fill = Variáveis)) +
geom_bar(stat = "identity", position = "dodge") +
theme_tufte()
ggpc + coord_flip() +
theme(axis.text.y = element_text(size=rel (1.2))) +
ylab("partidas/gols") +
xlab("")
Sintomática a realização de tantos jogos amistosos, pois é fato
notório que o futebol brasileiro, que nessa época se tornou produto de
exportação, ganhou enorme prestígio após a conquista do bicampeonato
mundial pela seleção, sucesso a meu ver emparelhado com o time do
Santos, onde desfilava, entre tantos, o craque
Pelé.
Listamos a seguir os jogos amistosos
disputados por Pelé, por diferentes equipes.
df2 <- df1 %>% filter(Competição == "Amistoso")
gpa <- agrupar1(df2, Equipe, partidas)
gpa
## # A tibble: 13 × 3
## Equipe partidas gols
## <chr> <int> <int>
## 1 Santos 378 383
## 2 Brasil 69 51
## 3 NY Cosmos 41 27
## 4 6º GAC 6 10
## 5 Seleção Paulista 4 2
## 6 All-Stars 2 0
## 7 Brasil (não oficial) 2 1
## 8 Fluminense 2 0
## 9 SAPESP 2 3
## 10 Seleção Militar Brasileira 2 3
## 11 Comb. Brasil 1 1
## 12 Ex-NY Cosmos 1 0
## 13 Flamengo 1 0
ggpa <- ggplot(data = gpa %>% gather(Variáveis, partidas, -Equipe),
aes(x = reorder(Equipe, +partidas), y = partidas, fill = Variáveis)) +
geom_bar(stat = "identity", position = "dodge") +
theme_tufte()
ggpa + coord_flip() +
theme(axis.text.y = element_text(size=rel (1.2))) +
ylab("partidas/gols") +
xlab("")
Listamos os adversários que mais sofreram com a genialidade de Pelé.
gpad <- agrupar1(df1, Adversário, gols)
gpad
## # A tibble: 391 × 3
## Adversário partidas gols
## <chr> <int> <int>
## 1 Corinthians 50 51
## 2 Guarani 35 45
## 3 Portuguesa 52 43
## 4 Juventus-SP 29 42
## 5 Botafogo-SP 29 40
## 6 Palmeiras 56 32
## 7 São Paulo 49 32
## 8 Noroeste 18 29
## 9 Prudentina 11 25
## 10 XV de Piracicaba 18 25
## # ℹ 381 more rows
gpad10 <- gpad %>%
arrange(desc(gols)) %>%
slice(1:10)
ggpad <- ggplot(data = gpad10 %>% gather(Variáveis, partidas, -Adversário),
aes(x = reorder(Adversário, +partidas), y = partidas, fill = Variáveis)) +
geom_bar(stat = "identity", position = "dodge") +
theme_tufte()
ggpad + coord_flip() +
theme(axis.text.y = element_text(size=rel (1.2))) +
ylab("partidas/gols") +
xlab("")
Revelamos os placares que mais se repetiram em sua carreira.
placares <- agrupar2(df1, Placar, partidas)
placares
## # A tibble: 66 × 3
## Placar partidas prop
## <chr> <int> <dbl>
## 1 2–1 112 8.16
## 2 1–1 98 7.14
## 3 1–0 83 6.05
## 4 3–1 80 5.83
## 5 2–0 72 5.24
## 6 3–0 66 4.81
## 7 1–2 60 4.37
## 8 0–0 59 4.30
## 9 3–2 59 4.30
## 10 2–2 58 4.22
## # ℹ 56 more rows
plac10 <- placares %>%
arrange(desc(partidas)) %>%
slice(1:10)
ggplot(plac10, aes(x = reorder(Placar, -partidas), y = partidas)) +
geom_bar(stat = "identity") +
labs(title = "Os placares mais comuns na carreira de Pelé", x = "Placares", y = "Partidas") +
theme_tufte() +
theme(panel.background = element_rect (fill = "white", colour = "black"))
Em uma época em que o futebol se tornou um negócio bilionário, reclama-se do calendário. Curiosamente, Pelé fez gols em todos os dias da semana.
df$Dds <- lubridate::wday(df$Data, week_start=1, label = TRUE)
gds <- df %>% group_by(Dds) %>%
reframe(Partidas = length(Dds), Gols = sum(Gols)) %>%
arrange(desc(Gols))
gds
## # A tibble: 7 × 3
## Dds Partidas Gols
## <ord> <int> <int>
## 1 dom 485 424
## 2 qua 363 362
## 3 sáb 174 163
## 4 qui 135 125
## 5 ter 100 97
## 6 sex 81 80
## 7 seg 35 36
ggplot(data = gds %>% gather(Variáveis, partidas, -Dds),
aes(x = Dds, y = partidas, fill = Variáveis)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Gols da semana", x = "Dia da semana", y = "Partidas/gols") +
theme_tufte()
Três resultados possíveis
Ganhar ou perder faz parte do jogo, tanto que, com Pelé em campo, as equipes pelas quais atuou também sofreram derrotas. Vejamos a seguir o desenrolar final das partidas.
placar <- lapply(df1$Placar, function(x) {
list(as.integer(strsplit(x, "–")[[1]][1]), as.integer(strsplit(x, "–")[[1]][2]))
})
df1$Resultado <- sapply(placar, function(x) {
if (x[[1]] > x[[2]]) {
return("Vitória")
} else if (x[[1]] < x[[2]]) {
return("Derrota")
} else {
return("Empate")
}
})
df1$Resultado <- as.numeric(factor(df1$Resultado))
status <- df1 %>% group_by(Resultado) %>%
reframe(partidas = length(Resultado)) %>%
mutate(Resultado = ifelse(Resultado == 3, "Vitória", ifelse(Resultado == 1, "Empate", "Derrota")))
status %>%
arrange(desc(partidas))
## # A tibble: 3 × 2
## Resultado partidas
## <chr> <int>
## 1 Vitória 890
## 2 Empate 250
## 3 Derrota 233
ggplot(data = status, aes(x = "", y = partidas, fill = Resultado)) +
geom_bar(stat = "identity") +
labs(title = "Resultados das partidas disputadas por Pelé", x = "", y = "")
Conclusão
Muito já foi dito e escrito a respeito do Rei Pelé.
Aproveitamos a existência de tabelas livremente disponíveis na
web para criar uma base de dados, que foi manipulada no
R, para revelar algumas peculiaridades ofuscadas pelos
números. Demonstramos como o uso de funções pode ser útil para
reduzir o tamanho do código.
Acho que tornamos o mito mais humano.
Mas é isto que torna heróico os grandes feitos. Por que a grandiosidade
de Pelé não se revela somente nos números. Está
inclusive nos gols que não foram marcados, mas que fizeram história. Nas
majestosas imagens plásticas.
Referências
Bradley Boehmke, Bradley (2018). “Scraping Data: UC Business
Analytics R Programming Guide”. https://uc-r.github.io/scraping#scraping_HTML_tables.
Kabacoff, Robert I. (2011). R in Action - Data analysis and graphics
with R. Maning Publications Co. Katti, Vishall (2021). “Programming with
R{Dplyr} - As I Undestand it”” July 17, 2021. https://vishalkatti.com/posts/programming-with-dplyr.