nba底层球员_探索个人NBA球员

nba底层球员

入门

在本系列的第1部分中,您学习了数据科学和机器学习的基础知识。 您使用Jupyter Notebook,Pandas和scikit-learn探索了NBA球队与其估值之间的关系。 在这里,您将探索社交媒体,薪水和NBA球员在场上表现之间的关系。

创建一个统一的数据框架(警告:继续努力!)

首先,创建一个新的Jupyter Notebook,并将其命名为nba_player_power_influence_performance

接下来,加载有关播放器的所有数据,并将数据合并到一个统一的数据帧中。

处理几个数据框架属于数据科学辛勤工作的80%。 在清单1和2中,复制了篮球参考数据框,然后重命名了几列。

清单1.设置Jupyter Notebook和加载数据框
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")
清单2.在正负数据框中修复列中的不良数据
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()

将NAME列重命名为PLAYER列的命令输出如下所示。 多余的列也被删除。 记下inplace=TRUE并将其放置到现有数据帧。

图1. NBA数据集的加载和描述
该图显示了命令的输出

下一步是重命名并合并包含“ 篮球参考 ”中大部分统计数据的核心数据框。 为此,请使用清单3和清单4中提供的代码。

清单3.重命名和合并篮球参考数据框
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()
清单4.清理和合并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()

图2显示了将列分为两部分并重新创建列的输出。 拆分和重新创建列是一种典型的操作,在解决数据科学问题时会占用大量数据处理时间。

图2.合并PIE数​​据帧
该图显示了5行x 37列的数据

到目前为止,大多数数据操作任务都相对简单。 由于缺少记录,事情将变得更加困难。 在清单5中,有111条工资记录缺失。 解决此问题的一种方法是进行合并,以删除丢失的行。 有很多技术可以处理丢失的数据。 如示例所示,仅删除丢失的行并不总是最佳选择。 在《 泰坦尼克号:灾难中的机器学习》中有许多处理缺失数据的示例。 值得花时间探索那里的一些示例笔记本。

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

在清单6中,您可以看到如何创建一个集合来计算缺少数据的行数。 这是一个方便的技巧,对于确定两个数据帧之间的区别是非常宝贵的。 这是通过使用Python内置函数len()来完成的,该函数在常规Python编程中也常用来获取列表的长度。

清单6.查找丢失的记录并合并
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)

输出如下所示。

图3.数据帧之间的差异
该图显示了数据帧之间的差异

数据框合并完成后,就该创建一个关联热图,以发现哪些特征被关联了。 下面的热图显示了35列和342行的相关性的组合输出。 突然出现的几件事是工资与积分和WINS_RPM都高度相关,WINS_RPM是一种高级统计数据,用于计算球员在场上为球队增加的估计胜利。

另一个有趣的关联是Wikipedia的页面浏览量与Twitter的“收藏夹”数量密切相关。 从直觉上讲,这种关联是有意义的,因为它们既是球迷参与度和对球迷的欢迎程度的度量。 这是一个可视化如何帮助确定哪些功能将进入机器学习模型的示例。

图4. NBA球员相关性热度图:2016-2017赛季(数据和薪水)
热图

在初步发现了哪些要素相关之后,下一步就是通过在Seaborn中绘图来进一步发现数据中的关系。 下面显示了运行图所执行的命令。

清单7.薪水对WINS_RPM的影响
sns.lmplot(x="SALARY_MILLIONS", y="WINS_RPM", data=nba_players_with_salary_df)

在下面显示的绘图输出中,工资和WINS_RPM之间似乎存在很强的线性关系。 要对此进行进一步调查,请运行线性回归。

图5. Seaborn薪水和实际加负的总和
该图显示了薪水百万x轴,y轴获胜

下面是关于获胜的两个线性回归的输出。 更有趣的发现之一是,WINS_RPM对赢的解释比对分数的解释要多。 对于WINS_RPM,R平方(拟合优度)为0.324,而点数为0.200。 WINS_RPM是显示归因于玩家的个人胜利的统计数据。 有意义的是,考虑到防守和进攻统计数据以及在球场上的时间,更高级的统计数据比进攻统计数据更具预测性。

在实际中如何发挥这种作用的一个例子是,想象一个球员的投篮命中率很低,但得分很高。 如果他经常投篮,而不是拥有更高投篮命中率的队友,那可能会损失他的胜利。 这种情况在2015-16赛季的现实生活中发挥得淋漓尽致,去年科比·布莱恩特在洛杉矶湖人队任职的那个赛季,他每个赛季拿下17.6分,但两分球命中率高达41%。 球队最终只赢了17场比赛,而WINS_RPM的统计数据是0.66( 本赛季只有半场胜利归功于他的表现 )。

图6.线性回归获胜
该图显示了线性获胜数据
清单8.回归获胜和积分
results = smf.ols('W ~POINTS', data=nba_players_with_salary_df).fit()
print(results.summary())

以图形方式表示这种关系的另一种方法是使用Python中的ggplot。 清单9是如何设置绘图的示例。 Python中的库是Rggplot的直接端口,并且正在积极开发中。 截至撰写本文时,它不如常规R ggplot平滑使用,但它具有许多不错的功能。 该图如下所示。
注意:方便的功能是能够用一种颜色表示另一列连续变量。

清单9. Python ggplot
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")
图7. Python ggplot加上减薪点
该图显示了胜利/ rpm x轴,积分/游戏y轴
抢夺NBA球员的Wikipedia页面浏览量

下一个任务是弄清楚如何收集Wikipedia页面视图,这通常是一个凌乱的数据收集。 问题包括:

  1. 弄清楚如何从Wikipedia(或某些网站)检索数据
  2. 弄清楚如何以编程方式生成Wikipedia句柄
  3. 将数据写入数据帧并将其与其余数据连接

以下代码在本教程的GitHub存储库中。 有关此代码的注释在以下各节中。

清单10提供了构建返回JSON响应的Wikipedia URL的代码。 在第1部分中,在文档字符串中显示了构造路径。 这是代码调用以获取页面视图数据的URL。

清单10. Wikipedia,第1部分
"""
Example Route To Construct:

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

在清单10的第2部分中,通过猜测名字和姓氏是玩家的名字来创建Wikipedia句柄,然后在出现错误的情况下尝试将“(basketball)”附加到URL。 这解决了大多数情况,并且仅丢失了几个名称/句柄。 一个示例猜测是姓“ LeBron”和姓“ James”。 最初以这种方式进行猜测的原因是,它与Wikipedia页面的匹配率接近80%,并节省了查找URL的时间。 对于不符合该模式的20%的名称,还有另一种方法(如下所示)可以匹配80%的初始缺失。

通过添加“篮球”,维基百科可以区分一个著名的名字和另一个著名的名字。 该约定捕获了大多数不匹配的名称。 清单10的第2部分显示了查找其他名称的最后一种方法。

清单10. Wikipedia,第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

在清单10的第3部分中,可以通过访问球员名单来简化对手柄的猜测。 这部分代码针对本文前面收集的整个NBA名册运行上面显示的匹配代码。

清单10. Wikipedia,第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

在清单10的第4部分中,整个脚本使用CSV文件作为输入运行,并使另一个CSV文件作为输出运行。 请注意,Wikipedia Python库用于检查页面以在最终匹配项中找到单词“ NBA”。 这是对通过多种猜测技术失败的页面的最后检查。 所有这些启发式方法的结果是一种为NBA运动员获取Wikipedia句柄的相对可靠的方法。 您可以想象使用类似的技术进行其他运动。

清单10. Wikipedia,第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()

吸引NBA球员的Twitter参与度

现在,您需要Twitter库,以便可以下载NBA球员的推文。 清单11,第1部分显示了使用此代码的API。 Twitter API比下面显示的简单脚本更高级。 这是使用已开发多年的第三方库的优点之一。

清单11. Twitter提取元数据,第1部分
"""
Get status on 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

在下一部分中,提取这些推文并将其转换为将值存储为中值的熊猫数据框。 通过仅存储我们感兴趣的值(即,一组数据的中位数),这是压缩数据的出色技术。 中位数是有用的指标,因为它对异常值具有鲁棒性。

清单11. Twitter提取元数据,第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")

创建高级可视化

通过添加社交媒体数据,您可以创建具有更多见解的更高级的地块。 图8是一个高级图,称为热图。 它显示了一组压缩的关键特征的相关性。 这些功能是进行更多机器学习(例如集群)的重要基础(请参阅本系列的第1部分 )。 值得您自己使用这些数据尝试不同的群集配置。

图8. NBA球员认可,社交能力,场上表现,球队估值相关性热图:2016-17赛季
热图

清单12提供了创建关联热图的代码。

清单12.相关热图
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")

清单13显示了一个热图,其中包含使用对数刻度创建的颜色以及一个特殊的颜色图。 这是在每个单元格之间提供鲜明对比的绝妙技巧。 对数刻度是显示相对变化与实际变化的转换。 当值的微分幅度较大时(例如10和1000万),通常在绘图中使用该技术。 显示相对变化与实际变化的关系可以使图更加清晰。 通常,绘图以线性比例(直线)显示。 对数刻度(对数线)在绘制时会降低功率(表示变平)。

清单13.高级关联热图
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)
图9. NBA球员认可,社交能力,场上表现,球队估值热图:2016-17赛季
该图显示了热图
最后一个绘图使用R语言在ggplot中创建多维绘图。 如清单14和图10所示。R中的本机ggplot库是功能强大且独特的图表库,可以创建具有颜色,大小,构面和形状的多个尺寸。 R中的ggplot库非常值得花时间独自探索。
清单14.基于R的高级ggplot
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)
图10. NBA球员的社会力量:2016-17赛季
该图显示了最终结果的图表NBA球迷对球员技能的重视程度超过薪水,积分或其他因素

结论

在本系列的第1部分中,您学习了机器学习的基础知识,并使用了无监督的聚类技术来探索团队的价值。 用于此数据科学的工具是Python和Jupyter Notebook的高级图形。

在第2部分中,您探讨了球员及其与社交媒体,影响力,薪水和场上表现的关系。 在Jupyter笔记本中创建了许多高级图形,但也有一个简短的R。

有些问题暴露或需要进一步调查(它们可能是错误的假设):

  • 支付给玩家的薪水并不是赢球的最好预测。
  • 粉丝与高技能运动员的互动更多(例如,相对于高薪运动员)。
  • 代言收入与球队为一名球员赢得的胜利数相关,因此他们可能要谨慎选择转入哪支球队。
  • 似乎有不同的观众亲自参加游戏,也有与社交媒体互动的观众。 如果他们的团队不熟练,那么面对面的观众似乎会感到困扰。

还有更多您可以做。 尝试将有监督和无监督的机器学习应用于GitHub中提供的数据集。 我已经上传了数据集供您在Kaggle上进行此项目的实验。


翻译自: https://www.ibm.com/developerworks/opensource/library/ba-social-influence-python-pandas-machine-learning-r-2/index.html

nba底层球员

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值