Análise Exploratória de Dados com Python: Extraindo insights do FIFA 18

Olá, bem vindo de volta!

Neste artigo vamos aprender a fazer uma tarefa muito importante no dia-a-dia de um Cientista de Dados. Faremos uma Análise Exploratória de Dados (do inglês, EDA). Para isso vamos fazer uso mais uma vez da linguagem de programação Python, através da distribuição Anaconda e da IDE Spyder.

 

Introdução

 

Antes de  mais nada, vamos definir o que exatamente é essa tal de EDA e por que, no meio de tantas coisas legais para se fazer com Machine Learning estamos nos preocupando com isso.

Basicamente EDA é a tarefa de se examinar os dados de uma base previamente à aplicação de qualquer outra técnica. Essa ação é importante pois permite que o Cientista de Dados tenha um entendimento básico do dataset que está trabalhando e das relações existentes entre as variáveis. Isso é feito empregando técnicas de análise gráficas e de estatística descritiva com objetivo de obter o máximo de informações ocultas.

Você já se deparou com uma base de dados e ficou curioso sobre certas características de algumas variáveis? Já elaborou hipóteses sobre esses dados mas não soube como valida-las? São questões como essas que a Análise Exploratória busca responder.

A EDA definitivamente é uma etapa muito importante para um projeto de Data Science ser bem sucedido.

 

Fonte de dados

 

Para este pequeno tutorial eu decidi pegar uma base de dados em uma das fontes mais conhecidas no mundo dos Cientistas de Dados, o Kaggle. Esse site começou em 2010, funcionando como uma plataforma onde empresas e pesquisadores publicavam datasets e os usuários competiam entre si para criar os melhores modelos preditivos. Em março de 2017 foi comprado pelo Google. Hoje em dia é um portal repleto de conteúdo e é referência na área de Data Science.

Para nossa tarefa de EDA decidi trabalhar com a base de dados do FIFA 2018, um dos jogos de video-game mais famosos do mundo. Essa base possui dados de todos os jogadores do game bem como mais de 70 atributos. Sem mais delongas, vamos codar!

Importando e tratando os dados

 

Como sempre, a primeira coisa que iremos fazer é importar todas as bibliotecas que serão úteis ao longo do código. A medida que cada uma for sendo usada eu explico.

Vamos começar usando a função read_csv(), da biblioteca pandas, para importar nossos dados. O pandas é a principal biblioteca para manipulação de dados no Python, é o equivalente da dplyr da linguagem R. Para importar a base no Spyder usaremos o código abaixo:

Armazenamos a base no objeto chamado de data. Chamamos a função read_csv() e foi passado como primeiro parâmetro o diretório onde a base de dados está localizada. O Pandas possui uma rica documentação. Sugiro sempre dar uma olhada no site oficial antes de usar qualquer função desconhecida. Neste link você encontra tudo o que precisa saber sobre a read_csv(). Vamos dar uma olhada nos primeiros registros do objeto data:

Como podemos ver, existem colunas com URLs, as quais não nos interessam. Vamos implementar algumas mudanças na base. Primeiro vamos deletar todas as colunas que não iremos usar:

Em seguida, usamos o comando data.dtypes (verifica o tipo dado em cada coluna) para constatar que a coluna Wage (salário) está como string. Perceba que os registros dessa coluna estão todos seguidos de K, exemplo, Cristiano Ronaldo — 565 K; Neymar — 280 K. Vamos então tirar esse K e transformar todos os registros para o tipo numérico:

Usando mais uma vez a função data.dtypes, percebemos que existem algumas colunas que estão como string (object) mas deveriam estar como número, como é o caso de Acceleration, Agility entre outras. Vamos então tentar passar essas colunas para o tipo inteiro usando o método mais fácil:

Isso resultará na seguinte mensagem de erro: ValueError: invalid literal for int() with base 10: ’60+6′. Bizarramente muitas colunas possuem valores como esse, um X+Y no lugar de um número. Vamos então criar uma função para transformar todo valor que está dessa forma para um número:

Usaremos um loop for para percorrer todas as colunas (9 até a 44) que possuem esse tipo de problema:

Pronto! Passamos da fase de preparação dos dados. Vamos agora entrar na análise propriamente dita. A partir desse ponto, se você tem conhecimento de SQL, verá muitas semelhanças entre algumas funções da biblioteca Pandas e as ferramentas de banco de dados.

A primeira informação útil que iremos extrair da base de dados é a quantidade nacionalidades sendo representadas:

Vamos agora descobrir os países com maior número de jogadores. Podemos fazer isso de duas formas:

As duas linhas de código retornam as mesma lista com o número de jogadores para cada país. Os que possuem a maior quantidade de representantes são:

Agora vamos dar uma olhada na variável Age:

Temos que a média de idade é 25.14 anos. Vamos tentar descobrir quantos representantes para cada idade existem:

Que resulta na seguinte lista:

Surpreendentemente existe um jogador de 47 anos! Podemos fazer também para a média de idade por clube:

Utilizando a função group by, do Pandas, fomos capazes de agrupar a média de idade por clube e armazenar os valores em uma serie (objeto semelhante a um dataframe mas que possui somente uma coluna além do index)  chamada de mediaPorClub: 

Nesta parte do dataframe podemos ver que a média de Idade no Botafogo fica em torno de 29 anos, enquanto que no Boca Juniors é na casa dos 24. Navegando por esse dataframe podemos ver a média de todos os clubes.

Usando somente a função group by podemos tirar diversos insights interessantes:

Nas últimas duas linhas usamos a função agg() para juntar os valores selecionados dentro dos colchetes, no caso: valor mínimo, máximo e a média. A coluna Overall significa a nota geral de cada atleta e o potencial, obviamente, representa uma expectativa de desempenho futuro do atleta.

 

Respondendo perguntas pontuais

 

Agora vamos buscar responder algumas perguntas pontuais e para isso, faremos bastante uso da função group by.

  • Quais são os melhores clubes baseado na média de Overall?

Fizemos basicamente o mesmo dos comandos anteriores. Agrupamos as médias de Overall por Club através do group by, ordenamos os valores de forma decrescente e guardamos o output numa serie chamada de mediaOverallPorClub, que ficou assim:

Seguindo essa lógica, descobrimos que os melhores clubes são o Barcelona, Juventus e Real Madrid. Porém, calcular os melhores clubes pela média pode não ser uma boa ideia, por conta da presença de outliers (pontos que destoam dos demais). Por exemplo, com certeza o Overall do Messi e do Cristiano Ronaldo influenciaram nesse cálculo, pois são de fato, jogadores incomuns. Vamos descobrir os melhores clubes de outra forma daqui a pouco. Por enquanto, vamos para a próxima pergunta.

  • Quais os jogadores com maior precisão no cabeceio?

Para responder essa pergunta, só precisamos ordenar os valores da coluna referente ao cabeceio fazendo uso da função sort_values().

Desta vez, armazenamos o resultado em um outro dataframe, chamado de cabeceio, que está ordenado da melhor nota para a pior:

  • Quais os goleiros com melhores reflexos?

Para esta pergunta fizemos uma alteração no objeto data. Criamos uma nova coluna, chamada de posição, que é uma cópia da Preferred Positions. Fizemos isso para usar com mais facilidade, na linha debaixo, uma string method, que é basicamente um conjunto de funções do Pandas feitas para se trabalhar com variáveis textuais. Você pode encontrar todas essas funções nesse link. Com o comando goleiros = data[data.posicao.str.contains(‘GK’)== True], selecionamos todos os registros que possuem o código GK, que se refere a posição de goleiro e com isso, colocamos todos os atletas que ocupam essa posição no dataframe que chamamos de goleiros. Então, usamos mais uma vez a função sort_values() para ordenador da maior nota no quesito reflexo, para a menor e a armazenamos na serie chamada de reflexosMelhoresGoleiros:

Surpreendentemente vemos o goleiro campeão do mundo pela Alemanha, Manuel Neuer, aparecer somente na quarta posição.

Podemos usar a função sort_values() para descobrir os melhores em diversos atributos, como o jogador mais rápido e o que possui maior potência no chute:

  • Qual é o melhor time?

Agora a pergunta mais curiosa de todos! O primeiro passo para responde-la é fazer mais uma alteração no nosso dataframe principal. Vamos deixar a coluna Preferred Positions somente com a melhor posição onde o jogador atua (anteriormente ela estava com todas as posições onde o jogador poderia atuar). Para isso faremos uso mais uma vez de uma função para strings:

Agora a coluna Preferred Positions possui somente um registro para cada jogador. Para descobrir os melhores em cada posição, vamos fazer uso de uma função criada por um usuário Kaggle lá de Hong Kong. Este é o link do perfil dele.

Essa função basicamente recebe uma lista de posições (position) como parâmetro e então percorre uma cópia do dataframe principal para buscar os jogadores com nota mais alta em cada uma das posições selecionadas na lista. Cada posição possui um código, como a do goleiro, que é GK. Por exemplo, atacante é ST, CDM é volante defensivo, CM é meia etc.

Tendo executado a função get_best_squad, podemos descobrir os melhores times para cada formação em campo (4-3-3, 3-5-2, 4-4-2 etc). Vamos começar com a formação 4-3-3:

Temos que o melhor time é:

Para a formação 3-5-2, temos que o melhor time é:

Visualizações

Agora vamos fazer uso de alguns recursos gráficos que o Python nos oferece. Usando os recursos de plotagem nativos do Pandas:

Perceba que escolhi como tipo de gráfico o histograma. Ele é um tipo de visualização muito simples que nos permite observar a distribuição de valores para uma única variável. Quando analisamos a distribuição dos dados não nos interessa valores individuais. Diferentemente do gráfico de barras, que tem como objetivo representar valores absolutos. A últimas duas linhas de código resultam nas seguintes visualizações:

Distribuição de Idade

 

Distribuição de Overall

Como era de se esperar, os dois gráficos mostraram distribuições que se aproximam da normal. Podemos melhorar a qualidade das visualizações fazendo uso de bibliotecas próprias para tal, como a Bokeh, que importamos no início do código. Vamos ver como se comporta a distribuição de idade nos melhores clubes:

Esse código resulta em uma bela visualização oriunda de um arquivo HTML que é aberto no seu browser padrão:

Vamos olhar agora os salários dos melhores clubes através de um boxplot. Para este gráfico usaremos a biblioteca seaborn, que é outra poderosa ferramenta de visualização em Python. Lembra de como funciona um boxplot? Ele é um retângulo com duas retas, uma na parte superior indicando o valor máximo e outra na parte inferior, referente ao valor mínimo. O retângulo é formado por três quartis. Da uma olhada na figura abaixo para ver como os dados são distribuídos em um boxplot:

Vamos agora construir nosso boxplot usando a biblioteca seaborn, que importamos no início do código como sns.

Tem como output o seguinte gráfico:

Como era de se esperar, a distribuição dos dados mostra alguns valores outliers, que certamente são os salários e grandes estrelas como Neymar, Messi e Cristiano Ronaldo.

No último passo na parte de visualização, vamos voltar a questão da descoberta dos melhores times. No começo deste artigo fizemos a média de Overall por clube mas chegamos a conclusão que não foi uma forma muito confiável, por conta da presença de outliers. Vamos então mudar de estratégia:

A primeira coisa que fizemos no código acima foi criar um novo dataframe somente com os jogadores com Overall maior que 85. Em seguida agrupamos esses jogadores por clube e contamos quantos atletas cada clube possui. Com isso chegamos em uma lista dos clubes que possuem maior quantidade de jogadores com avaliação alta (escolhi Overall acima de 85 aleatoriamente).  Por fim, plotamos o resultado através da biblioteca seaborn, passando os parâmetros solicitados pelas funções. Obtivemos o seguindo gráfico:

 

Correlações

 

E como última etapa deste tutorial, vamos analisar algumas correlações. É importante lembrar que a existência de uma correlação significativa entre duas variáveis, não implica necessariamente em uma relação de causalidade entre elas. Uma correlação indica um ponto a ser estudado com maior rigor científico para comprovar ou não um vínculo de causa e efeito. A imagem abaixo demonstra as possíveis relações entre duas variáveis, onde r é o valor da correlação.

 

Para analisar as correlações no Python faremos uso da função corr(), do Pandas, para calcular os valores de r e também usaremos a função heatmap(), da seaborn, para visualizar os valores de forma mais amigável. Porém, antes vamos criar um novo data frame, contendo somente as colunas mais interessantes para se analisar as correlações. Lembrando que o dataframe principal possui mais de 70 atributos. Seria inviável e visualmente nada agradável analisar tantas variáveis.

Ao executar o código acima, obtemos a seguinte matriz:

Lembrando que precisamos ignorar a diagonal principal, pois se trata da relação de uma variável com si mesma. A partir da última imagem podemos comprovar diversas relações intuitivas, como Idade e Overall e Aceleração e Agilidade.

E esse foi o tutorial de hoje pessoal, o mais simples que já fiz até agora. Espero que tenham curtido. Qualquer dúvida não deixem de entrar em contato comigo.

Abraço

 

Referências

 

Galera, como de costume usei as seguintes referências para este artigo:

  • Os cursos da Formação Cientista de Dados da Data Science Academy. O melhor caminho para iniciar nessa área!
  • O sensacional blog Minerando Dados. Se você curte Data Science, não deixe de acompanhar o que essa galera posta lá.
  • Projeto do nosso amigo de Hong Kong lá no Kaggle.
Article By :