Gols de Pelé

Guilherme Ferreira

2023-05-09

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.