GraphGists

简介

每年 NBA 的季后赛都会吸引全球数十亿观众和巨额资金。博彩公司拥有自己的秘密算法来计算每场比赛的投注赔率。一支拥有良好胜率记录的球队当然更有可能获胜。但是,那些历史战绩参差不齐的球队呢?我不是赌徒,但我对背后的算法很感兴趣。

问题

通常,要确定两支球队之间的胜率,您可以查看它们之间过往比赛的历史:总胜场和总负场;但如果这两支球队之前从未交手过,或者更可能的是,在最近几年(尤其是 NBA 总决赛,一支来自东部,另一支来自西部)从未交手过呢?一种比较方法是计算它们的胜率:(总胜场)/(总比赛场数)。但是,考虑到每支球队主要(或者有时专门)与自己联盟的球队比赛,因此胜率可能无法进行很好的比较。

解决方案

通过图数据库中的路径概念,不仅可以轻松计算传统的统计数据,还可以引入新的方法,通过季后赛链将任意两支球队联系起来。如果我们将两支交手过的球队视为连接,并且这种连接关系可以传递,那么所有参加某一年季后赛的球队都是连接的,无论是直接还是间接;或者,如果我们将多个年份的季后赛合并在一起,那么所有参加 NBA 季后赛的球队都是连接的。基于这些连接,可以利用最短路径来查找任意两支球队之间的最密切关系。如果我们将数值分配给这些连接,则可以使用可衡量的机制来比较任意两支球队。

数据模型

  • 每支 NBA 球队是一个节点 [共 30 个节点]

  • 每轮季后赛(不是单场比赛,而是整轮比赛)是一个节点 [每年 15 轮]

  • 每轮季后赛的结果将存储在边中;每条边的方向将是从球队到轮次,并且该边中将存储获胜场数 [0,1,2,3,4]

设置

设置代码将加载 2013 年、2014 年和 2015 年 NBA 季后赛结果作为示例数据到图数据库中。

单一年份的 NBA 季后赛

显示整个 2015 年季后赛结果。

MATCH (t)-[]->(p:Playoff)
WHERE p.Year = "2015"
RETURN t,p

球队的历史季后赛

显示单个球队的全部历史季后赛。

MATCH (t:Team {Name: "Golden State"})-[w:WIN]->(:Playoff)<-[l:WIN]-()
RETURN t,w,l

计算胜率

列出过去 3 年中每支球队的全部历史胜场和负场。

MATCH (t:Team)-[w:WIN]->(:Playoff)<-[l:WIN]-()
RETURN t.Name as TEAM, SUM(w.Win) AS TOTAL_WIN, SUM(l.Win) as TOTAL_LOSS,
(toFloat(SUM(w.Win)) / (toFloat(SUM(w.Win))+ toFloat(SUM(l.Win)))) as WIN_PERCENTAGE
ORDER BY SUM(w.Win) DESC

如果两支球队之前交手过:显示两支球队之间的季后赛历史

如果两支球队之前交手过,则以下查询将列出它们的所有比赛。

MATCH (t1:Team {Name: "Miami"})-[r1:WIN]->(p:Playoff)<-[r2:WIN]-(t2:Team {Name:"San Antonio"})
RETURN t1,r1,p,r2,t2

如果两支球队之前交手过:计算胜场和负场

对于两支之前交手过的球队,可以使用它们的胜率来预测哪支球队更强。

MATCH (t1:Team {Name: "Miami"})-[r1:WIN]->(p:Playoff)<-[r2:WIN]-(t2:Team {Name:"San Antonio"})
RETURN p.Year as Year,r1.Win as Miami,r2.Win as San_Antonio
ORDER BY p.Year DESC

在上述案例中,圣安东尼奥和迈阿密在过去 3 年的季后赛中交手了 12 场比赛,圣安东尼奥赢了 7 场,输了 5 场。因此,如果他们在 2016 年 NBA 总决赛中再次相遇,圣安东尼奥可能会有略高的获胜几率。

如果两支球队之前从未交手过:简单示例

查找两支球队之间的所有最短路径

MATCH (t1:Team {Name: "Miami"}),(t2:Team {Name:"Portland"}),
	p = AllshortestPaths((t1)-[*..14]-(t2))
RETURN p
MATCH p= AllShortestPaths((t1:Team {Name: "Miami"})-[:WIN*0..14]-(t2:Team {Name:"Portland"}))
WITH extract(r IN relationships(p)| r.Win) AS RArray
RETURN RArray

在上述案例中,一条路径 [1,4,4,1] 表明这两支球队可能拥有相同的获胜几率,但迈阿密在另一条路径 [4,3,4,,1] 中显示出略微的优势。因此,我们可以说如果迈阿密与波特兰在总决赛中相遇,迈阿密更有可能获胜。

如果两支球队之前从未交手过:复杂示例

查找两支球队之间的所有最短路径

MATCH (t1:Team {Name: "Golden State"}),(t2:Team {Name:"Toronto"}),
	p = AllshortestPaths((t1)-[*..14]-(t2))
RETURN p
MATCH (t1:Team {Name: "Golden State"}),(t2:Team {Name:"Toronto"}),
	p = AllshortestPaths((t1)-[r:WIN*..14]-(t2))
WITH r,p,extract(r IN relationships(p)| r.Win ) AS paths
RETURN paths

上述案例比简单示例更复杂:分别有 6 条最短路径,每条路径都有 8 个关系。因此,我引入了一个名为平均净胜场的概念,它是每条路径的平均净胜场,其中 [净胜场] = [总胜场] - [总负场] 在一条最短路径中。当从球队 A 到球队 B 的平均净胜场为正时,球队 A 优于球队 B。

MATCH p= AllShortestPaths((t1:Team {Name: "Golden State"})-[:WIN*0..14]-(t2:Team {Name:"Toronto"}))
WITH extract(r IN relationships(p)| r.Win) AS RArray, LENGTH(p)-1  as s
RETURN AVG(REDUCE(x = 0, a IN [i IN range(0,s) WHERE i % 2 = 0 | RArray[i] ] | x + a)) //total win
- AVG(REDUCE(x = 0, a IN [i IN range(0,s) WHERE i % 2 <> 0 | RArray[i] ] | x + a)) //total loss
AS NET_WIN

扩展当前模型

上面描述的模型只是简单地使用原始的胜场和负场数量来在比较期间建议布尔结果。如果我们希望对更多球队进行排名或建立更准确的可量化的评级系统,可以向模型中引入更多元素——例如,球场可以帮助在分析过程中将主场优势纳入考虑;或者为季后赛的不同轮次分配权重,以便在计算最短路径上的平均净胜场时,NBA 总决赛的净胜场数比第一轮的净胜场数具有更大的影响。