#-----------------------------------------------------------------------
#                                            Prof. Dr. Walmes M. Zeviani
#                                leg.ufpr.br/~walmes · github.com/walmes
#                                        walmes@ufpr.br · @walmeszeviani
#                      Laboratory of Statistics and Geoinformation (LEG)
#                Department of Statistics · Federal University of Paraná
#                                       2019-jun-01 · Curitiba/PR/Brazil
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# Carrega os pacotes.

import see
import numpy as np
import pandas as pd

# Versões.
np.__version__ # '1.16.4'
pd.__version__ # '0.24.2'

#-----------------------------------------------------------------------
# Importação dos dados sobre os jogadores de futebol do Brasileirão.

# Funções que começam com "read_".
[d for d in dir(pd) if "read_" in d]

# Pode usar 2016, 2017 ou 2018.
url = "http://leg.ufpr.br/~walmes/data/jogadores-brasileirao-2018.txt"
bra8 = pd.read_csv(filepath_or_buffer = url,
                   delimiter = "\t",
                   comment = "#")

# Estrutura do objeto.
bra8.info()

# Métodos e atributos.
see.see(bra8)

#-----------------------------------------------------------------------
# Questões e soluções.

# Qual a dimensão da tabela?
bra8.shape

# Qual o nome das variáveis.
bra8.columns

# Quais as variáveis e seus tipos de valor?
bra8.dtypes

# Qual a classe do objeto?
type(bra8)

# Quais os métodos disponíveis para a(s) classe(s) dele?
see.see(pd.core.frame.DataFrame)

# Qual o tamanho dos times (número de jogadores)?
bra8['TeamName'].value_counts()

# Quantos jogadores em cada função (goleiro, zagueiro, etc)?
bra8['PositionText'].value_counts()

# O item anterior mas em termos proporcionais e não absolutos?
bra8['PositionText'].value_counts(normalize = True)

# Qual a distribuição de frequência para o número de gols?
bra8['Goals'].\
    value_counts().\
    reset_index().\
    rename(columns = {"index": "Goals", "Goals": "Freq"}).\
    assign(Prop = lambda x: x.Freq/x.Freq.sum())

# Como incluir todos os valores entre o 0 e máximo número de goals?
v = pd.DataFrame({"Goals": np.arange(start = 0,
                                     stop = bra8['Goals'].max() + 1,
                                     step = 1)})
u = pd.merge(left = u,
             right = v,
             how = 'right',
             on = list(v.columns.values),
             sort = True).\
             fillna(value = 0)
u

# Como ordenar os jogadores pela altura de maneira descrescente?
bra8.\
    sort_values(['Height'], ascending = False).\
    loc[:, ['Name', 'TeamName', 'Height', 'Weight', 'Age']]

# Como colocar NaN para a altura dos jogadores tem quem altura 0
# (NaN incoerente = propriedade de validade)?
bra8['Height'].replace(to_replace = 0, value = np.nan, inplace = True)
bra8['Height'].isna().sum()

# Como ordenar de forma crescente pela idade seguido de descrescente
# pela altura?
bra8.\
    sort_values(['Age', 'Height'], ascending = [True, False]).\
    loc[:, ['Name', 'TeamName', 'Age', 'Height', 'Weight']]

# Como filtrar apenas para os jogadores do Palmeiras?
bra8.query('TeamName == "Palmeiras"').\
    loc[:, ['Name', 'TeamName', 'Age', 'Height', 'Weight']]

bra8[bra8['TeamName'] == "Palmeiras"].\
    loc[:, ['Name', 'TeamName', 'Age', 'Height', 'Weight']]

# Como filtrar para Palmeiras e Corinthians apenas?
bra8[bra8['TeamName'].isin(["Palmeiras", "Corinthians"])].\
    loc[:, ['Name', 'TeamName', 'Age', 'Height', 'Weight']]

# Filtrar apenas os goleiros.
bra8[bra8['PositionText'] == "Goalkeeper"].\
    loc[:, ['Name', 'TeamName', 'PositionText',
            'Age', 'Height', 'Weight']]

# Filtrar só para os goleiros do Gremio.
bra8[(bra8['PositionText'] == "Goalkeeper") &\
     (bra8['TeamName'] == "Gremio")].\
     loc[:, ['Name', 'TeamName', 'PositionText',
             'Age', 'Height', 'Weight']]

# Como tirar uma amostra aleatória de 10 jogadores?
bra8.sample(n = 10).\
    loc[:, ['Name', 'TeamName', 'PositionText', 'Age', 'Rating']]

# Como tirar uma amostra aleatória de 12 jogadores sendo 3 de cada
# posição em joga?
bra8.groupby(['PositionText']).\
    apply(lambda x: x.sample(n = 3)).\
    loc[:, ['Name', 'TeamName', 'PositionText', 'Age', 'Rating']]

# Como criar uma variável com o signo de cada jogador?
dts = {"Aquário": "20/01", "Peixes": "19/02", "Áries": "21/03",
       "Touro": "20/04", "Gêmeos": "21/05", "Câncer": "22/06",
       "Leão": "23/07", "Virgem": "23/08", "Libra": "23/09",
       "Escorpião": "23/10", "Sagitário": "22/11",
       "Capricórnio": "22/12"}
signo = pd.Series(list(dts.keys()))
dts = pd.Series(list(dts.values()))
dts = dts + "/2016" # Foi ano bissexto.

# Converte para a classe de data.
dts = pd.to_datetime(arg = dts, format = "%d/%m/%Y")

# Dia juliano (dia no ano) para quebrar as datas.
jul = pd.DatetimeIndex(dts).\
      strftime('%j').\
      astype(int).\
      to_series()

# Cria os signos.
x = pd.to_datetime(arg = bra8['DateOfBirth'],
                   format = "%Y-%m-%d")
x = pd.DatetimeIndex(x).\
    strftime('2016-%m-%d')
x = pd.DatetimeIndex(x).\
    strftime('%j').\
    astype(int).\
    to_series()
x = pd.cut(x = x,
           bins = jul,
           labels = signo[:-1],
           right = False)

# Onde tem NA é Capricórnio (datas na extremidades, Dezembro e Janeiro).
x.value_counts(sort = False, dropna = False)

# Coloca Capricórnio onde é NaN.
x.replace(to_replace = np.nan,
          value = signo.tail(n = 1).values[0],
          inplace = True)

x.value_counts(sort = False, dropna = False)

# Mudar a ordem dos níveis para começar em Áries.
x = pd.Categorical(values = x,
                   categories = signo[2:].append(signo[:2]),
                   ordered = True)
pd.Series(x).value_counts(sort = False)

# Adiciona a variável na tabela.
bra8['Sign'] = pd.Series(x)

# Apenas confere se a quebra nas datas ficou certa.
i = bra8['DateOfBirth'].str.endswith(pat = '01-19')
bra8[['DateOfBirth', 'Sign']][i]
i = bra8['DateOfBirth'].str.endswith(pat = '01-20')
bra8[['DateOfBirth', 'Sign']][i]

# Distribuição das datas de nascimento dos jogadores é uniforme ao longo
# do ano? Ou seja, todos os signos ocorrem em igual proporção?
bra8['Sign'].\
    value_counts(sort = True).\
    reset_index().\
    assign(freq = lambda x: x.Sign/x.Sign.sum()).\
    rename(columns = {"index": "Sign", "Sign": "n"})

# Qual o total de gols de cada time?
bra8.groupby(['TeamName']).agg({"Goals": ["sum"]})

# Qual é conversão de chutes em gols para cada time?
bra8.groupby(['TeamName']).\
    apply(lambda x: x.Goals.sum()/x.TotalShots.sum()).\
    sort_values(ascending = False)

# Como calcular a soma de gols, cartões amarelos e vermelhos por time.
bra8.groupby(['TeamName'])[['Goals', 'Yellow', 'Red']].sum(axis = 1)

# Como obter o total de gols por time e função em campo e exibir isso
# com times nas linhas, posição em campo nas colunas e total de gols em
# cada cédula?
bra8.groupby(['TeamName', 'PositionText'])[['Goals']].\
    sum().\
    reset_index().\
    pivot(index = 'TeamName',
          columns = 'PositionText',
          values = 'Goals')

# O mesmo de antes mas usando o Rating médio.
bra8.groupby(['TeamName', 'PositionText'])[['Rating']].\
    mean().\
    reset_index().\
    pivot(index = 'TeamName',
          columns = 'PositionText',
          values = 'Rating')

# O mesmo de antes mas os números sendo o número de jogadores em cada
# posição em cada time.
bra8.groupby(['TeamName', 'PositionText'])[['Rating']].\
    size().\
    reset_index().\
    rename(columns = {0: "n"}).\
    pivot(index = 'TeamName',
          columns = 'PositionText',
          values = 'n')

# Calcular média, mediana, desvio-padrão e desvio absoluto médio da
# mediana para o número de gols dos atacantes por time? Detalhe,
# usando nomes definidos pelo usuário.
bra8.query('PositionText == "Forward"').\
    groupby(['TeamName'])[['Goals']].\
    agg(['mean', 'median', 'std', 'mad']).\
    reset_index()

# Como fazer quando a função retorna vetor de comprimento maior que 1?
bra8.\
    groupby(['TeamName'])[['Height']].\
    apply(lambda x: x.quantile([0.25, 0.75])).\
    reset_index().\
    rename(columns = {"level_1": "percentil"})

# Como obter os percentis para várias variáveis?
bra8.\
    groupby(['TeamName'])[['Age', 'Height', 'Weight']].\
    apply(lambda x: x.quantile([0.1, 0.25, 0.5, 0.75, 0.9])).\
    reset_index().\
    rename(columns = {"level_1": "percentil"})

# Quanto maior a altura maior é o ganho em disputas de bolas áereas?
bins = bra8['Height'].quantile(np.linspace(0, 1, num = 11))
bra8['h_group'] = pd.cut(x = bra8['Height'], bins = bins)
bra8['prop_gan'] = bra8['AerialWon']/(bra8['AerialWon'] + \
                                      bra8['AerialLost'])
bra8.groupby(['h_group']).agg({"prop_gan": ["mean", "size"]})

#-----------------------------------------------------------------------
# Importar os dados de 2016 e 2017.

url = "http://leg.ufpr.br/~walmes/data/jogadores-brasileirao-2016.txt"
bra6 = pd.read_csv(filepath_or_buffer = url,
                   delimiter = "\t",
                   comment = "#")

url = "http://leg.ufpr.br/~walmes/data/jogadores-brasileirao-2017.txt"
bra7 = pd.read_csv(filepath_or_buffer = url,
                   delimiter = "\t",
                   comment = "#")

# Quais os jogadores que mudaram de time de 2016 para 2017?
v = ['PlayerId', 'Name', 'TeamName', 'Rating']
res = pd.merge(left = bra6[v],
               right = bra7[v],
               how = 'inner',
               on = v[0:2],
               suffixes = ['16', '17'])

# Jogadores que trocaram de time de 2016 para 2017.
res.\
    query('TeamName16 != TeamName17').\
    filter(regex = "Name")

# Em qual time houve mais troca de jogador?
res.\
    query('TeamName16 != TeamName17').\
    filter(regex = "Name")['TeamName16'].\
    value_counts()

# Quantos jogadores melhoraram o Rating (ou não) de 2016 para 2017.
res.\
    query('TeamName16 == TeamName17').\
    assign(cresceu = lambda x: x.Rating17 > x.Rating16)['cresceu'].\
    value_counts()

# Qual o time que teve a maior proporção de jogadores com aumento de
# rating de 2016 para 2017?
res.\
    query('TeamName16 == TeamName17').\
    assign(cresceu = lambda x: x.Rating17 > x.Rating16).\
    groupby(['TeamName16']).\
    agg({"cresceu": "mean",
         "Rating16": "mean",
         "Rating17": "mean"}).\
         sort_values('cresceu', ascending = False)

# Qual o total de gols de cada jogador em cada campeonato para aqueles
# que jogaram nos 3 anos? Exibir os gols nas colunas.
bra6['Year'] = 2016
bra7['Year'] = 2017
bra8['Year'] = 2018
bra = pd.concat([bra6, bra7, bra8],
                axis = 0,
                join = 'inner',
                ignore_index = True)
bra.info()

# Tem situação em que o jogador mudou de time.
i = bra.duplicated(); i.sum()
pid = bra.PlayerId[i].sort_values(); pid

bra[["PlayerId", "Name", "Year", "TeamName", "Rating", "Goals"]]\
    [bra.PlayerId.isin(pid)].\
    sort_values(['Name', 'Year'])

bra[["PlayerId", "Name", "Year", "TeamName", "Goals"]].\
    groupby(['PlayerId', 'Name', 'Year']).\
    Goals.sum().\
    unstack(level = -1).\
    reset_index().\
    dropna()

# Quantos jogadores novos surgiram de 2016 para 2017 e para 2018 em cada
# time?
def count_news(x, y):
    return(np.setdiff1d(y, x).size)

u = bra.\
    groupby(['TeamName', 'Year']).\
    apply(lambda x: list(x.PlayerId)).\
    unstack().\
    reset_index().\
    dropna().\
    rename(columns = str)

u.columns
u.index.values

u['from16to17'] = [count_news(x = u[["2016"]].loc[i, :][0],
                              y = u[["2017"]].loc[i, :][0])
                   for i in u.index]
u['from17to18'] = [count_news(x = u[["2017"]].loc[i, :][0],
                              y = u[["2018"]].loc[i, :][0])
                   for i in u.index]

u[['TeamName', 'from16to17', 'from17to18']]

# Quem foi o artilheiro em cada ano?
bra[["TeamName", "Year", "Name", "Rating", "Goals", "PositionText"]].\
    groupby(['Year']).\
    apply(lambda x: x[x.Goals == x.Goals.max()])

bra[["TeamName", "Year", "Name", "Rating", "Goals", "PositionText"]].\
    groupby(['Year']).\
    apply(lambda x: x.nlargest(n = 1, columns = 'Goals', keep = 'all'))

# Quem foi o jogador de maior rating em cada ano?
bra[["TeamName", "Year", "Name", "Rating", "Goals", "PositionText"]].\
    groupby(['Year']).\
    apply(lambda x: x.nlargest(n = 1, columns = 'Rating', keep = 'all'))

#-----------------------------------------------------------------------
