Conteúdo


Poder social, influência e desempenho na NBA, Parte 2

Explorando os jogadores individuais da NBA

Python, pandas e um toque de R

Comments

Conteúdos da série:

Esse conteúdo é a parte # de # na série: Poder social, influência e desempenho na NBA, Parte 2

Fique ligado em conteúdos adicionais dessa série.

Esse conteúdo é parte da série:Poder social, influência e desempenho na NBA, Parte 2

Fique ligado em conteúdos adicionais dessa série.

Em Parte 1 desta série, você aprendeu o básico da ciência de dados e do aprendizado de máquina. Você usou Jupyter Notebook, pandas e scikit-learn para explorar o relacionamento entre os times da NBA e suas avaliações. Aqui, você vai explorar o relacionamento entre mídia social, salário e desempenho na quadra dos jogadores na NBA.

Criar um quadro de dados unificado (aviso: essa é uma tarefa trabalhosa!)

Para começar, crie um novo Jupyter Notebook e nomeie-o como nba_player_power_influence_performance.

Em seguida, carregue todos os dados sobre os jogadores e mescle os dados em um único quadro de dados unificado.

A manipulação dos vários quadros de dados cai na categoria de 80 por cento da parte trabalhosa da ciência de dados. Nas listagens 1 e 2, o quadro de dados basketball-reference é copiado e, em seguida, várias colunas são renomeadas.

Listagem 1. Configurando o Jupyter Notebook e carregando os quadros de dados

import pandas as pd
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
color = sns.color_palette()
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
%matplotlib inline
attendance_valuation_elo_df = pd.read_csv("../data/nba_2017_att_val_elo.csv")
salary_df = pd.read_csv("../data/nba_2017_salary.csv")
pie_df = pd.read_csv("../data/nba_2017_pie.csv")
plus_minus_df = pd.read_csv("../data/nba_2017_real_plus_minus.csv")
br_stats_df = pd.read_csv("../data/nba_2017_br.csv")

Listagem 2. Corrigindo os dados inválidos no quadro de dados mais menos

plus_minus_df.rename(columns={"NAME":"PLAYER"}, inplace=True)
players = []
for player in plus_minus_df["PLAYER"]:
    plyr, _ = player.split(",")
    players.append(plyr)
plus_minus_df.drop(["PLAYER"], inplace=True, axis=1)
plus_minus_df["PLAYER"] = players
plus_minus_df.head()

O resultado dos comandos para renomear a coluna NAME para a coluna PLAYER é mostrado abaixo. A coluna extra também é descartada. Observe o inplace=TRUE e os descartes a serem aplicados ao quadro de dados existente.

Figura 1. Carregar e descrever o conjunto de dados da NBA
Image shows output of commands
Image shows output of commands

O próximo passo é renomear e mesclar o quadro de dados principal que contém a maioria das estatísticas de Referência de Basquete. Para fazer isso, use o código fornecido nas listagens 3 e 4.

Listagem 3. Renomear e mesclar o quadro de dados de referência de basquete

nba_players_df = br_stats_df.copy()
nba_players_df.rename(columns={'Player': 'PLAYER','Pos':'POSITION', 'Tm': "TEAM", 'Age': 'AGE'}, inplace=True)
nba_players_df.drop(["G", "GS", "TEAM"], inplace=True, axis=1)
nba_players_df = nba_players_df.merge(plus_minus_df, how="inner", on="PLAYER")
nba_players_df.head()

Listagem 4. Limpar e mesclar os campos do PIE

pie_df_subset = pie_df[["PLAYER", "PIE", "PACE"]].copy()
nba_players_df = nba_players_df.merge(pie_df_subset, how="inner", on="PLAYER")
nba_players_df.head()

A Figura 2 mostra o resultado da divisão das colunas em duas partes e a recriação da coluna. Dividir e recriar colunas é uma operação típica e consome a maior parte do tempo da manipulação de dados para resolver problemas de ciência de dados.

Figura 2. Mesclar os quadros de dados do PIE
Image shows 5 rows x 37 columns  of data
Image shows 5 rows x 37 columns of data

Até agora, a maioria das tarefas de manipulação de dados foram relativamente fáceis. A partir de agora, vai ficar mais difícil porque há registros ausentes. Na Listagem 5, há 111 registros de salário ausentes. Uma maneira de lidar com isso é fazer uma mesclagem que descarte as linhas ausentes. Há várias técnicas para lidar com dados ausentes, pois apenas descartar as linhas ausentes, como é mostrado no exemplo, nem sempre é a melhor opção. Há vários exemplos de como lidar com dados ausentes em Titanic: aprendizado de máquina por meio de um desastre . Vale a pena dedicar um tempo para explorar alguns exemplos de notebooks que se encontram lá.

Listagem 5. Limpar o salário

salary_df.rename(columns={'NAME': 'PLAYER'}, inplace=True)
salary_df.drop(["POSITION","TEAM"], inplace=True, axis=1)
salary_df.head()

Na Listagem 6, é possível ver como um conjunto é criado para calcular o número de linhas com dados ausentes. Esse é um truque útil de grande valor para determinar qual é a diferença entre dois quadros de dados. Ele é realizado usando a função integrada do Python len(), que também geralmente é usada na programação em Python regular para obter o comprimento de uma lista.

Listagem 6. Encontrar registros ausentes e mesclar

diff = list(set(nba_players_df["PLAYER"].values.tolist()) - set(salary_df["PLAYER"].values.tolist()))
len(diff)

Out[45]:  111
nba_players_with_salary_df = nba_players_df.merge(salary_df)

O resultado é mostrado abaixo.

Figura 3. Diferença entre quadros de dados
Image shows difference between data frames
Image shows difference between data frames

Com as mesclagens de quadro de dados concluídas, é hora de criar um mapa de calor de correlação para descobrir quais recursos estão correlacionados. O mapa de calor abaixo mostra o resultado combinado da correlação de 35 colunas e 342 linhas. Uma das coisas imediatas que podem ser observadas é que o salário está altamente correlacionado aos pontos e ao WINS_RPM, que é uma estatística avançada que calcula a estimativa de partidas vencidas que um jogador agrega ao time quando ele está na quadra.

Outra correlação interessante é que as visualizações na página da Wikipédia estão fortemente correlacionadas às contagens de favoritos do Twitter. Essa correlação faz sentido intuitivamente porque ambas são medidas de engajamento e popularidade dos jogadores da NBA pelos fãs. Este é um exemplo de como a visualização pode ajudar a identificar exatamente quais recursos entrarão em um modelo de aprendizado de máquina.

Figura 4. Mapa de calor de correlação de jogadores da NBA: temporada 2016/2017 (estatística e salário)
heatmap
heatmap

Com uma descoberta inicial de quais recursos estão correlacionados, o próximo passo é descobrir outros relacionamentos nos dados, plotando no Seaborn. Os comandos executados para executar o plot são mostrados abaixo.

Listagem 7. lmplot do Seaborn de salário versus WINS_RPM

sns.lmplot(x="SALARY_MILLIONS", y="WINS_RPM", data=nba_players_with_salary_df)

No resultado do plot mostrado abaixo, parece haver um forte relacionamento linear entre o salário e o WINS_RPM. Para investigar mais isso, execute uma regressão linear.

Figura 5. Implot do Seaborn de mais menos de salário e partidas vencidas
Image shows salary millions x  axis, wins y axis
Image shows salary millions x axis, wins y axis

O resultado das duas regressões lineares sobre as partidas vencidas está abaixo. Uma das descobertas mais interessantes é que as partidas vencidas são mais explicadas pelo WINS_RPM do que pelos pontos. O R quadrado (bondade do ajuste) é 0,324 no caso de WINS_RPM versus 0,200 em pontos. O WINS_RPM é a estatística que mostra as partidas vencidas individuais atribuídas a um jogador. É compreensível que uma estatística mais avançada que considere estatísticas de ataque e defesa e o tempo na quadra seja mais preditiva do que uma estatística apenas de ataque.

Um exemplo de como isso seria na prática é imaginar um jogador com uma porcentagem de lançamentos muito baixa, mas com muitos pontos. Se ele lançasse a bola com mais frequência, em vez de um outro jogador com uma porcentagem de lançamentos mais alta, isso o custaria partidas vencidas. Esse caso ocorreu na vida real durante a temporada de 2015/16, quando Kobe Bryant, em seu último ano no Los Angeles Lakers, teve 17,6 pontos por temporada, mas uma porcentagem de lançamentos de 41 por cento para dois ponteiros. O time acabou vencendo apenas 17 jogos e a estatística WINS_RPM foi 0,66 (somente meia partida vencida atribuída à sua jogada durante a temporada).

Figura 6. Partidas vencidas de regressão linear
Image shows  linear  wins data
Image shows linear wins data

Listagem 8. Partidas vencidas e pontos de regressão

results = smf.ols('W ~POINTS', data=nba_players_with_salary_df).fit()
print(results.summary())

Outra maneira de representar esse relacionamento graficamente é com ggplot em Python. A Listagem 9 é um exemplo de como configurar o plot. A biblioteca em Python é uma porta direta do ggplot em R e está em desenvolvimento ativo. No momento em que este artigo foi escrito, ele não era tão fácil de usar quanto o ggplot do R regular, mas tinha vários recursos interessantes. O gráfico é mostrado abaixo.
Nota: Um recurso útil é a capacidade de representar outra coluna de variáveis contínuas por uma cor.

Listagem 9. ggplot do Python

from ggplot import *
p = ggplot(nba_players_with_salary_df,aes(x="POINTS", y="WINS_RPM", color="SALARY_MILLIONS")) + geom_point(size=200)
p + xlab("POINTS/GAME") + ylab("WINS/RPM") + ggtitle("NBA Players 2016-2017:  POINTS/GAME, WINS REAL PLUS MINUS and SALARY")
Figura 7. Pontos de salário menos mais do ggplot do Python
Image shows wins/rpm x axis, points/game y axis
Image shows wins/rpm x axis, points/game y axis

Capturando as visualizações de páginas da Wikipédia para jogadores da NBA

A próxima tarefa é descobrir como coletar visualizações de páginas da Wikipédia, que geralmente é uma coleta de dados complicada. Os problemas incluem:

  1. Descobrir como recuperar os dados da Wikipédia (ou de algum outro website)
  2. Descobrir como gerar programaticamente os identificadores da Wikipédia
  3. Gravar os dados em um quadro de dados e reuni-los com o restante dos dados

O código abaixo está no repositório do GitHub deste tutorial. Há comentários sobre esse código ao longo das seções abaixo.

A Listagem 10 fornece o código para construir uma URL da Wikipédia que retorne uma resposta JSON. Na Parte 1, no docstrings, é mostrada a rota para a construção. Essa é a URL que o código chama para obter os dados da visualização da página.

Listagem 10. Wikipédia, parte 1

"""
Rota de exemplo para construção:

https://wikimedia.org/api/rest_v1/ +
metrics/pageviews/per-article/ +
en.wikipedia/all-access/user/ +
LeBron_James/daily/2015070100/2017070500 +

"""
import requests
import pandas as pd
import time
import wikipedia

BASE_URL =\
 "https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia/all-access/user"

def construct_url(handle, period, start, end):
    """Constructs a URL based on arguments

    Should construct the following URL:
    /LeBron_James/daily/2015070100/2017070500 
    """

    
    urls  = [BASE_URL, handle, period, start, end]
    constructed = str.join('/', urls)
    return constructed

def query_wikipedia_pageviews(url):

    res = requests.get(url)
    return res.json()

def wikipedia_pageviews(handle, period, start, end):
    """Returns JSON"""

    constructed_url = construct_url(handle, period, start,end)
    pageviews = query_wikipedia_pageviews(url=constructed_url)
    return pageviews

Na Listagem 10, parte 2, os identificadores da Wikipédia são criados adivinhando que o nome e o sobrenome sejam o nome do jogador e, em seguida, tentando anexar "(basketball)" à URL, caso haja algum erro. Isso resolve a maioria dos casos, e somente alguns nomes/identificadores são perdidos. Uma adivinhação de exemplo seria "LeBron" como nome e "James" como sobrenome. O motivo para adivinhar dessa forma inicialmente é que esse padrão corresponde a 80 por cento das páginas da Wikipédia e economiza o tempo de procurar as URLs uma por uma. Para os 20 por cento de nomes que não se encaixam nesse padrão, há um outro método (mostrado abaixo) que corresponde a 80 por cento dessas perdas iniciais.

Ao adicionar "(basketball)", a Wikipédia consegue diferenciar entre um nome famoso e outro. Essa convenção captura a maioria dos nomes que não correspondem inicialmente. A Listagem 10, parte 2, mostra o último método para localizar os outros nomes.

Listagem 10. Wikipédia, parte 2

def wikipedia_2016(handle,sleep=0):
    """Retrieve pageviews for 2016""" 
    
    print("SLEEP: {sleep}".format(sleep=sleep))
    time.sleep(sleep)
    pageviews = wikipedia_pageviews(handle=handle, 
            period="daily", start="2016010100", end="2016123100")
    if not 'items' in pageviews:
        print("NO PAGEVIEWS: {handle}".format(handle=handle))
        return None
    return pageviews

def create_wikipedia_df(handles):
    """Creates a Dataframe of Pageviews"""

    pageviews = []
    timestamps = []    
    names = []
    wikipedia_handles = []
    for name, handle in handles.items():
        pageviews_record = wikipedia_2016(handle)
        if pageviews_record is None:
            continue
        for record in pageviews_record['items']:
            pageviews.append(record['views'])
            timestamps.append(record['timestamp'])
            names.append(name)
            wikipedia_handles.append(handle)
    data = {
        "names": names,
        "wikipedia_handles": wikipedia_handles,
        "pageviews": pageviews,
        "timestamps": timestamps 
    }
    df = pd.DataFrame(data)
    return df    


def create_wikipedia_handle(raw_handle):
    """Takes a raw handle and converts it to a wikipedia handle"""

    wikipedia_handle = raw_handle.replace(" ", "_")
    return wikipedia_handle

def create_wikipedia_nba_handle(name):
    """Appends basketball to link"""

    url = " ".join([name, "(basketball)"])
    return url

Na Listagem 10, parte 3, a adivinhação de um identificador é facilitada pelo acesso a uma lista de jogadores participantes. Essa parte do código executa o código correspondente mostrado acima em relação à lista de participantes da NBA inteira coletada anteriormente no artigo.

Listagem 10. Wikipédia, parte 3

def wikipedia_current_nba_roster():
    """Gets all links on wikipedia current roster page"""

    links = {}
    nba = wikipedia.page("List_of_current_NBA_team_rosters")
    for link in nba.links:
        links[link] = create_wikipedia_handle(link)
    return links

def guess_wikipedia_nba_handle(data="data/nba_2017_br.csv"):
    """Attempt to get the correct wikipedia handle"""

    links = wikipedia_current_nba_roster() 
    nba = pd.read_csv(data)
    count = 0
    verified = {}
    guesses = {}
    for player in nba["Player"].values:
        if player in links:
            print("Player: {player}, Link: {link} ".format(player=player,
                 link=links[player]))
            print(count)
            count += 1
            verified[player] = links[player] #add wikipedia link
        else:
            print("NO MATCH: {player}".format(player=player))
            guesses[player] = create_wikipedia_handle(player)
    return verified, guesses

Na Listagem 10, parte 4, o script inteiro é executado usando o arquivo CSV como entrada e fazendo com que outro arquivo CSV funcione como resultado. Observe que a biblioteca Python da Wikipédia é usada para inspecionar a página para localizar a palavra "NBA" nas partidas finais. Essa é a última verificação para páginas que falharam em diversas técnicas de adivinhação. O resultado de toda essa heurística é uma maneira relativamente confiável de obter os identificadores da Wikipédia para os atletas da NBA. É possível imaginar o uso de técnicas semelhantes para outros esportes.

Listagem 10. Wikipédia, parte 4

def validate_wikipedia_guesses(guesses):
    """Validate guessed wikipedia accounts"""

    verified = {}
    wrong = {}
    for name, link in guesses.items():
        try:
            page = wikipedia.page(link)
        except (wikipedia.DisambiguationError, wikipedia.PageError) as error:
            #try basketball suffix
            nba_handle = create_wikipedia_nba_handle(name)
            try:
                page = wikipedia.page(nba_handle)
                print("Initial wikipedia URL Failed: {error}".format(error=error))
            except (wikipedia.DisambiguationError, wikipedia.PageError) as error:
                print("Second Match Failure: {error}".format(error=error))
                wrong[name] = link
                continue
        if "NBA" in page.summary:
            verified[name] = link
        else:
            print("NO GUESS MATCH: {name}".format(name=name))
            wrong[name] = link
    return verified, wrong

def clean_wikipedia_handles(data="data/nba_2017_br.csv"):
    """Clean Handles"""

    verified, guesses = guess_wikipedia_nba_handle(data=data)
    verified_cleaned, wrong = validate_wikipedia_guesses(guesses)
    print("WRONG Matches: {wrong}".format(wrong=wrong))
    handles = {**verified, **verified_cleaned}
    return handles

def nba_wikipedia_dataframe(data="data/nba_2017_br.csv"):
    handles = clean_wikipedia_handles(data=data)
    df = create_wikipedia_df(handles)    
    return df

def create_wikipedia_csv(data="data/nba_2017_br.csv"):
    df = nba_wikipedia_dataframe(data=data)
    df.to_csv("data/wikipedia_nba.csv")


if __name__ == "__main__":
    create_wikipedia_csv()

Capturando os engajamentos no Twitter para jogadores da NBA

Agora, a biblioteca do Twitter é necessária para que seja possível fazer o download dos tweets para jogadores da NBA. A Listagem 11, parte 1 mostra a API para usar esse código. A API do Twitter é mais avançada do que o script simples mostrado abaixo. Essa é uma das vantagens de usar uma biblioteca de terceiros que é desenvolvida há anos.

Listagem 11. Extrair metadados do Twitter, parte 1

"""
Veja o status no Twitter

df = stats_df(user="KingJames")
In [34]: df.describe()
Out[34]: 
       favorite_count  retweet_count
count      200.000000     200.000000
mean     11680.670000    4970.585000
std      20694.982228    9230.301069
min          0.000000      39.000000
25%       1589.500000     419.750000
50%       4659.500000    1157.500000
75%      13217.750000    4881.000000
max     128614.000000   70601.000000

In [35]: df.corr()
Out[35]: 
                favorite_count  retweet_count
favorite_count        1.000000       0.904623
retweet_count         0.904623       1.000000

"""

import time

import twitter
from . import config
import pandas as pd
import numpy as np
from twitter.error import TwitterError

def api_handler():
    """Creates connection to Twitter API"""
    
    api = twitter.Api(consumer_key=config.CONSUMER_KEY,
    consumer_secret=config.CONSUMER_SECRET,
    access_token_key=config.ACCESS_TOKEN_KEY,
    access_token_secret=config.ACCESS_TOKEN_SECRET)
    return api

def tweets_by_user(api, user, count=200):
    """Grabs the "n" number of tweets.  Defaults to 200"""

    tweets = api.GetUserTimeline(screen_name=user, count=count)
    return tweets

Nesta próxima seção, os tweets são extraídos e convertidos em um quadro de dados do pandas que armazena os valores como uma média. Essa é uma técnica excelente para compactar os dados armazenando apenas os valores em que estamos interessados (ou seja, a média de um conjunto de dados). A média é uma métrica útil porque ela demonstra bem os valores discrepantes.

Listagem 11. Extrair metadados do Twitter, parte 2

def stats_to_df(tweets):
    """Takes twitter stats and converts them to a dataframe"""

    records = []
    for tweet in tweets:
        records.append({"created_at":tweet.created_at,
            "screen_name":tweet.user.screen_name, 
            "retweet_count":tweet.retweet_count,
            "favorite_count":tweet.favorite_count})
    df = pd.DataFrame(data=records)
    return df

def stats_df(user):
    """Returns a dataframe of stats"""

    api = api_handler()
    tweets = tweets_by_user(api, user)
    df = stats_to_df(tweets)
    return df

def twitter_handles(sleep=.5,data="data/twitter_nba_combined.csv"):
    """yield handles"""

    nba = pd.read_csv(data) 
    for handle in nba["twitter_handle"]:
        time.sleep(sleep) #Avoid throttling in twitter api
        try:
            df = stats_df(handle)
        except TwitterError as error:
            print("Error {handle} and error msg {error}".format(
                handle=handle,error=error))
            df = None
        yield df

def median_engagement(data="data/twitter_nba_combined.csv"):
    """Median engagement on twitter"""

    favorite_count = []
    retweet_count = []
    nba = pd.read_csv(data)
    for record in twitter_handles(data=data):
        print(record)
        #None records stored as Nan value
        if record is None:
            print("NO RECORD: {record}".format(record=record))
            favorite_count.append(np.nan)
            retweet_count.append(np.nan)
            continue
        try:
            favorite_count.append(record['favorite_count'].median())
            retweet_count.append(record["retweet_count"].median())
        except KeyError as error:
            print("No values found to append {error}".format(error=error))
            favorite_count.append(np.nan)
            retweet_count.append(np.nan)
        
    print("Creating DF")
    nba['twitter_favorite_count'] = favorite_count
    nba['twitter_retweet_count'] = retweet_count
    return nba

def create_twitter_csv(data="data/nba_2016_2017_wikipedia.csv"):
    nba = median_engagement(data)
    nba.to_csv("data/nba_2016_2017_wikipedia_twitter.csv")

Criando visualizações avançadas

Com a adição de dados de mídia social, é possível criar plots mais avançados com insights adicionais. A Figura 8 é um plot avançado, chamado de mapa de calor. Ele mostra a correlação de um conjunto compactado de recursos principais. Esses recursos são um ótimo bloco de desenvolvimento para realizar mais aprendizado de máquina, como o armazenamento em cluster (consulte Parte 1 desta série). Esses dados podem ser usados em seu próprio experimento com diferentes configurações de armazenamento em cluster.

Figura 8. Patrocínio de jogadores da NBA, poder social, desempenho na quadra, mapa de calor de correlação de avaliação de time: temporada 2016/17
heatmap
heatmap

A Listagem 12 fornece o código para criar o mapa de calor de correlação.

Listagem 12. Mapa de calor de correlação

endorsements = pd.read_csv("../data/nba_2017_endorsement_full_stats.csv")
plt.subplots(figsize=(20,15))
ax = plt.axes()
ax.set_title("NBA Player Endorsement, Social Power, On-Court Performance, Team Valuation Correlation Heatmap:  2016-2017 Season")
corr = endorsements.corr()
sns.heatmap(corr, 
            xticklabels=corr.columns.values,
            yticklabels=corr.columns.values, cmap="copper")

A Listagem 13 mostra um mapa de calor com cores criadas usando uma escala de log, juntamente com um mapa de cores especiais. Esse é um ótimo truque para oferecer um contraste diferente entre cada célula. Uma escala de log é uma transformação que mostra a mudança relativa versus a mudança real. Essa é uma técnica comum usada em gráficos quando os valores têm uma grande magnitude de diferenciação — por exemplo, 10 e 10 milhões. Mostrar a mudança relativa versus a mudança real agrega mais clareza a um plot. Geralmente, um plot é mostrado em escala linear (uma linha reta). Uma escala de log (linha de log) tem sua força diminuída quando é plotada (o que significa que ela decai).

Listagem 13. Mapa de calor de correlação avançado

from matplotlib.colors import LogNorm
plt.subplots(figsize=(20,15))
pd.set_option('display.float_format', lambda x: '%.3f' % x)
norm = LogNorm()
ax = plt.axes()
grid = endorsements.select_dtypes([np.number])
ax.set_title("NBA Player Endorsement, Social Power, On-Court Performance, Team Valuation Heatmap:  2016-2017 Season")
sns.heatmap(grid,annot=True, yticklabels=endorsements["PLAYER"],fmt='g', cmap="Accent", cbar=False, norm=norm)
Figura 9. Patrocínio de jogador da NBA, poder social, desempenho na quadra, mapa de calor de avaliação de time: temporada 2016/17
Image shows heatmap
Image shows heatmap

Um último plot usa a linguagem R para criar um plot multidimensional em ggplot. Isso é mostrado na Listagem 14 e na Figura 10. A biblioteca ggplot nativa em R é uma biblioteca de gráficos poderosa e exclusiva que pode criar várias dimensões com cor, tamanho, aspectos e formas. Vale a pena dedicar um tempo para explorar a biblioteca ggplot em R por sua conta.

Listagem 14. ggplot baseado em R avançado

ggplot(nba_players_stats, aes(x=WINS_RPM, y=PAGEVIEWS,
                color=SALARY_MILLIONS, size=TWITTER_FAVORITE_COUNT)) + geom_point() +
                geom_smooth() + scale_color_gradient2(low = "blue", mid = "grey", high =
                "red", midpoint = 15) + labs(y="Wikipedia Median Daily Pageviews", x="WINS
                Attributed to Player( WINS_RPM)", title = "Social Power NBA 2016-2017
                Season: Wikipedia Daily Median Pageviews and Wins Attributed to Player
                (Adusted Plus Minus)") +
                geom_text(vjust="inward",hjust="inward",color="black",size=4,check_overlap
                = TRUE, data=subset(nba_players_stats, SALARY_MILLIONS > 25 | PAGEVIEWS
                > 4500 | WINS_RPM > 15), aes(WINS_RPM,label=PLAYER )) +
                annotate("text", x=8, y=13000, label= "NBA Fans Value Player Skill More
                Than Salary, Points, Team Wins or Another Other Factor?", size=5) +
                annotate("text", x=8, y=11000, label=paste("PAGEVIEWS/WINS Correlation:
                28%"),size=4) + annotate("text", x=8, y=10000,
                label=paste("PAGEVIEWS/Points Correlation 44%"),size=4) + annotate("text",
                x=8, y=9000, label=paste("PAGEVIEWS/WINS_RPM Correlation: 49%"),size=4,
                color="red") + annotate("text", x=8, y=8000,
                label=paste("SALARY_MILLIONS/TWITTER_FAVORITE_COUNT: 24%"),size=4)
Figura 10. Poder social do jogador da NBA: temporada 2016-17
Image shows chart with end result NBA fans value player skill more than salary, points, or other factors
Image shows chart with end result NBA fans value player skill more than salary, points, or other factors

Conclusão

Em Parte 1 desta série, você aprendeu o básico do aprendizado de máquina e usou técnicas de armazenamento em cluster não supervisionado para explorar a avaliação do time. As ferramentas utilizadas para essa ciência de dados foram o Python e os gráficos avançados com o Jupyter Notebook.

Aqui, na Parte 2, você explorou os jogadores e seus relacionamentos com a mídia social, a influência, o salário e o desempenho na quadra. Muitos gráficos avançados foram criados em um Jupyter Notebook, mas também houve um toque de R.

Algumas questões expostas ou que precisam de mais investigação (podem ser suposições erradas):

  • O salário pago aos jogadores não oferece a melhor previsão de partidas vencidas.
  • Os fãs engajam-se mais com atletas altamente qualificados (e não com os mais bem pagos, por exemplo).
  • A receita do patrocínio está correlacionada ao número de partidas vencidas que um time tem para um jogador, portanto, eles devem ser cuidadosos quanto ao time para o qual pretendem mudar.
  • Parece haver uma diferença entre o público que comparece pessoalmente aos jogos e o que se engaja nas mídias sociais. O público que comparece pessoalmente parece ficar incomodado quando falta qualificação para seu time.

É possível fazer muito mais. Tente aplicar o aprendizado de máquina supervisionado e não supervisionado ao conjunto de dados fornecido no GitHub. Eu fiz o upload do conjunto de dados para que você possa experimentar usando esse projeto no Kaggle.


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Big data e análise de dados, Software livre
ArticleID=1056813
ArticleTitle=Poder social, influência e desempenho na NBA, Parte 2: Explorando os jogadores individuais da NBA
publish-date=01192018