博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[译]剖析勇士如何成为新赛季夺冠热门:基于Spark GraphFrames的金州勇士传球网络分析...
阅读量:6125 次
发布时间:2019-06-21

本文共 6561 字,大约阅读时间需要 21 分钟。

rank

databricks 最近发布了 ,这是一个用 DataFrames 封装图处理过程的Spark插件。

我评估了网络分析并且利用丰富的的数据对金州勇士的传球网络进行可视化。

head

金州勇士的传球网络

传接球

联盟 MVP Stephen Curry 接到了大多数的传球,而团队中的 MVP Draymond Green则发动了最多的传球。

我们已经看到大多数的进攻是由 Curry 和 Green 的相互传球开始的。

图片来自

入度 inDegree

id inDegree
CurryStephen 3993
GreenDraymond 3123
ThompsonKlay 2276
LivingstonShaun 1925
IguodalaAndre 1814
BarnesHarrison 1241
BogutAndrew 1062
BarbosaLeandro 946
SpeightsMarreese 826
ClarkIan 692
RushBrandon 685
EzeliFestus 559
McAdooJames Michael 182
VarejaoAnderson 67
LooneyKevon 22

出度 outDegree

id outDegree
GreenDraymond 3841
CurryStephen 3300
IguodalaAndre 1896
LivingstonShaun 1878
BogutAndrew 1660
ThompsonKlay 1460
BarnesHarrison 1300
SpeightsMarreese 795
RushBrandon 772
EzeliFestus 765
BarbosaLeandro 758
ClarkIan 597
McAdooJames Michael 261
VarejaoAnderson 94
LooneyKevon 36

标签传递算法 (Label Propagation Algorithm)

标签传递是一种在图网络中寻找队伍的算法。

这种算法在没有已有标签的情况下,依然可以很好地将球员分为前锋和后卫。

名字 标签
Thompson, Klay 3
Barbosa, Leandro 3
Curry, Stephen 3
Clark, Ian 3
Livingston, Shaun 3
Rush, Brandon 7
Green, Draymond 7
Speights, Marreese 7
Bogut, Andrew 7
McAdoo, James Michael 7
Iguodala, Andre 7
Varejao, Anderson 7
Ezeli, Festus 7
Looney, Kevon 7
Barnes, Harrison 7

网页排名算法 (Pagerank Algorithm)

在一个网络中 PageRank 可以检测节点的重要程度。

毫无疑问,Stephen Curry、 Draymond Green 和 Klay Thompson 是Top3.
这个算法可以发现 Shaun Livingston 和 Andre Iguodala 在金州勇士的传球中扮演着关键角色。

name pagerank
Curry, Stephen 2.17
Green, Draymond 1.99
Thompson, Klay 1.34
Livingston, Shaun 1.29
Iguodala, Andre 1.21
Barnes, Harrison 0.86
Bogut, Andrew 0.77
Barbosa, Leandro 0.72
Speights, Marreese 0.66
Clark, Ian 0.59
Rush, Brandon 0.57
Ezeli, Festus 0.48
McAdoo, James Michael 0.27
Varejao, Anderson 0.19
Looney, Kevon 0.16

示例

library(networkD3)setwd('/Users/yuki/Documents/code_for_blog/gsw_passing_network')passes <- read.csv("passes.csv")groups <- read.csv("groups.csv")size <- read.csv("size.csv")passes$source <- as.numeric(as.factor(passes$PLAYER))-1passes$target <- as.numeric(as.factor(passes$PASS_TO))-1passes$PASS <- passes$PASS/50groups$nodeid <- groups$namegroups$name <- as.numeric(as.factor(groups$name))-1groups$group <- as.numeric(as.factor(groups$label))-1nodes <- merge(groups,size[-1],by="id")nodes$pagerank <- nodes$pagerank^2*100forceNetwork(Links = passes,             Nodes = nodes,             Source = "source",             fontFamily = "Arial",             colourScale = JS("d3.scale.category10()"),             Target = "target",             Value = "PASS",             NodeID = "nodeid",             Nodesize = "pagerank",             linkDistance = 350,             Group = "group",              opacity = 0.8,             fontSize = 16,             zoom = TRUE,             opacityNoHover = TRUE)

example

  • 节点大小: pagerank值

  • 节点颜色: 队伍

  • 连线宽度: 传球次数(接球和发球)

工作流

调用API

我使用 playerdashptpass 的端点并且将同队所有球员数据保存到本地的 JSON 文件中。

数据来自 2015-16赛季的传球记录。

# 金州勇士球员 IDsplayerids = [201575,201578,2738,202691,101106,2760,2571,203949,203546,203110,201939,203105,2733,1626172,203084]# 调用 API 并且存储结果为 JSONfor playerid in playerids:    os.system('curl "http://stats.nba.com/stats/playerdashptpass?'        'DateFrom=&'        'DateTo=&'        'GameSegment=&'        'LastNGames=0&'        'LeagueID=00&'        'Location=&'        'Month=0&'        'OpponentTeamID=0&'        'Outcome=&'        'PerMode=Totals&'        'Period=0&'        'PlayerID={playerid}&'        'Season=2015-16&'        'SeasonSegment=&'        'SeasonType=Regular+Season&'        'TeamID=0&'        'VsConference=&'        'VsDivision=" > {playerid}.json'.format(playerid=playerid))

JSON -> Panda’s DataFrame

接着,我结合每个JSON文件到一个 DataFrame 中。

raw = pd.DataFrame()for playerid in playerids:    with open("{playerid}.json".format(playerid=playerid)) as json_file:        parsed = json.load(json_file)['resultSets'][0]        raw = raw.append(            pd.DataFrame(parsed['rowSet'], columns=parsed['headers']))raw = raw.rename(columns={'PLAYER_NAME_LAST_FIRST': 'PLAYER'})raw['id'] = raw['PLAYER'].str.replace(', ', '')

准备节点和边

你需要为 Spark 中的 GraphFrames 准备一个像点+边的特殊的数据格式。顶点表示了图中的节点和运动员ID,边表示节点之间的关系。你可以添加一些附加特征比如权重,但是你没法找出在稍后的分析中可以更好表现的特征。一个可行的办法是尝试穷举所有的可能方案。(也欢迎大家留言讨论)

# 生成初始节点pandas_vertices = raw[['PLAYER', 'id']].drop_duplicates()pandas_vertices.columns = ['name', 'id']# 生成初始边pandas_edges = pd.DataFrame()for passer in raw['id'].drop_duplicates():    for receiver in raw[(raw['PASS_TO'].isin(raw['PLAYER'])) &     (raw['id'] == passer)]['PASS_TO'].drop_duplicates():        pandas_edges = pandas_edges.append(pd.DataFrame(            {'passer': passer, 'receiver': receiver            .replace(  ', ', '')},             index=range(int(raw[(raw['id'] == passer) &             (raw['PASS_TO'] == receiver)]['PASS'].values))))pandas_edges.columns = ['src', 'dst']

图分析

vertices = sqlContext.createDataFrame(pandas_vertices)edges = sqlContext.createDataFrame(pandas_edges)# Analysis partg = GraphFrame(vertices, edges)print("vertices")g.vertices.show()print("edges")g.edges.show()print("inDegrees")g.inDegrees.sort('inDegree', ascending=False).show()print("outDegrees")g.outDegrees.sort('outDegree', ascending=False).show()print("degrees")g.degrees.sort('degree', ascending=False).show()print("labelPropagation")g.labelPropagation(maxIter=5).show()print("pageRank")g.pageRank(resetProbability=0.15, tol=0.01).vertices.sort(    'pagerank', ascending=False).show()

网络可视化

当你运行 GitHub 仓库中的代码 ,你需要检查在工作目录下有 passes.csvgroups.csvsize.csv 这三个文件。我用R中的networkD3包来实现酷炫的可交互的 D3 制图。

library(networkD3)setwd('/Users/yuki/Documents/code_for_blog/gsw_passing_network')passes <- read.csv("passes.csv")groups <- read.csv("groups.csv")size <- read.csv("size.csv")passes$source <- as.numeric(as.factor(passes$PLAYER))-1passes$target <- as.numeric(as.factor(passes$PASS_TO))-1passes$PASS <- passes$PASS/50groups$nodeid <- groups$namegroups$name <- as.numeric(as.factor(groups$name))-1groups$group <- as.numeric(as.factor(groups$label))-1nodes <- merge(groups,size[-1],by="id")nodes$pagerank <- nodes$pagerank^2*100forceNetwork(Links = passes,             Nodes = nodes,             Source = "source",             fontFamily = "Arial",             colourScale = JS("d3.scale.category10()"),             Target = "target",             Value = "PASS",             NodeID = "nodeid",             Nodesize = "pagerank",             linkDistance = 350,             Group = "group",              opacity = 0.8,             fontSize = 16,             zoom = TRUE,             opacityNoHover = TRUE)

参考资料

本文已获得原作者: 授权HarryZhu翻译

英文原文地址:

作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者 Harry Zhu 的 FinanceR专栏:,如果涉及源代码请注明GitHub地址:。微信号: harryzhustudio

商业使用请联系作者。

你可能感兴趣的文章
mysql权限管理
查看>>
老虞要学GoLang-为什么会学习GoLang
查看>>
利用estools修改javascript源代码
查看>>
Redis构建分布式锁
查看>>
实现javascript下的模块组织
查看>>
制作思维导图的建议
查看>>
Linux中nfs网络文件共享
查看>>
free
查看>>
PHP环境下在SAE中使用Kindeditor操作Stroge
查看>>
JUNIPER SRX dynamic ***配置实验
查看>>
whenever
查看>>
大数据模块开发之数据采集
查看>>
SAP系统参数设置
查看>>
ubuntu下安装wine1.4
查看>>
nginx负载均衡实现https
查看>>
入门一班20181016 正则
查看>>
springmvc整个dubbo
查看>>
java 工作流项目源码 SSM 框架 Activiti-master springmvc
查看>>
35款超赞的设计常用的英文字体
查看>>
Android知识点总结
查看>>