十行代码预测插旗西雅图(上)

浏览: 1782

我错了,我承认我是标题党,怎么可能用十行代码完成 Dota2 比赛数据的抓取, 清洗与预测建模呢。 不过为了发扬继承郎大为“十行代码”系列的优良传统,我决定沿用这个名字,希望能把品牌做大做强,走出亚洲,面向世界。。。

事情的起因是这样的:上周与同为信仰粉的大为接上头之后,被安利了一个叫 RDota2的 R pacakge。 这个工具包使用 Steam API,可以让 R 直接提取有关 Dota2 的各种数据:除了每一场游戏的具体信息,还可以提取英雄,物品,战队,和联赛的资料。 所以我就萌生了用 RDota2 抓一批比赛数据,然后建模预测比赛胜负的想法。结果还是相当有趣的,且听我慢慢道来。 不过在此之前,我想先为对建模感兴趣但不知道什么是 Dota2 的同学,简单介绍一下这款游戏。

image.png

Dota2众型男

Dota2 来源于暴雪魔兽争霸的一张自定义地图,又叫 RPG 图,就是由地图开发者在魔兽争霸这个游戏之上自己创建了一种玩法。 这张地图的名字就叫做 Dota,Defense of the Ancient,被视为当下十分流行的 MOBA(多人在线战术竞技)类游戏的鼻祖, 简单说就是英雄联盟的爸爸,王者荣耀的爷爷。 MOBA 类游戏的核心机制是,两队玩家以摧毁对方大本营为获胜目标互相厮杀。 下面这张是 Dota2 实际游戏的截图,上边的就是其中一方的大本营,叫做天辉,下边的则是另一方,称为夜魇。 各自大本营的位置由红色箭头标注在地图上了,而整场比赛就发生在这张地图所代表的区域内,绿色的是天辉的势力范围,红色则是夜魇的。 大多数 MOBA 类游戏的对阵双方各有5名玩家,他们从各具特色的100多个英雄中选出一个操纵, 在游戏里与队友支援配合,与对手斗智斗勇,下图中的小人儿就是一位选出来的英雄了。 地图上除了大本营和玩家的化身英雄之外,还有不受玩家控制分属于两方的小兵和防御塔,但它们会主动攻击对方的单位, 而且虽然同一单位分属两边时的造型不同,它们的能力是完全相同的,不然比赛就有失公平。 每场比赛每个玩家都是从零开始,随着游戏的进行,操作英雄通过杀死对方小兵和英雄,积累金钱购买装备,获得经验升级技能。 开始的厮杀大多发生在红绿交接处,然后双方势力此消彼长,直到一方摧毁另一方的大本营赢得比赛胜利。 一场比赛的用时大概在半小时到一小时之间,当然也有十几分钟的短局,或者三四小时的膀胱局。

image.png

两锅汤底引发的血案

再回头说说 Dota 的历史,它的首个版本于03年由开发者 Eul 发布,中间更换好几次开发者之后, 由伟大的 Icefrog 冰蛙于05年开始接手开发至今,开启了一个传奇的时代。 我是从冰蛙接手后的6.41版本开始接触 Dota 的,那是07年因为实习必须留在学校的夏天。 这个版本我至今依然记忆深刻,当一件事不是为了生计,而是完全出于喜爱而持续做了十年的时候,就成为了一种信仰(庄严脸)。

image.png

6.48版本载入画面

当然很少有游戏能连续流行十几年。所以 Dota 的经久不衰要感谢 Dota2 的一波续命。 09年,拥有全球最大在线游戏销售平台 Steam 的游戏公司 Valve 看中了 Dota 的巨大潜力,把冰蛙招入麾下着手开发独立的一款游戏 Dota2, 使其摆脱魔兽争霸一张地图的身份。 为此还引发了反应慢半拍的暴雪和 Valve 之间的版权纠纷。 Dota2 所有理念和设计完全照搬 Dota,但因为能独立于魔兽争霸之外,新的引擎给 Dota2 更绚丽的画面,更流畅的手感,以及游戏本身更高的自由度。 但是 Dota2 在10年刚推出的时候,因为本身的完成度很低,Dota 本体还十分火热等原因,基本上没人能够或者愿意玩。 直到11年 Valve 在德国科隆游戏展上举办了首届 Dota2 国际竞标赛 The International (TI),Dota2 才成功展示了自己的存在。 Valve 的这一手“千金买马骨”玩得实在溜,要知道当时即使在电竞最发达的欧洲,各大比赛的奖金基本上就几千欧, 突然石破天惊来一个总奖金160万美元,冠军100万美元,这能不让世界各地的网瘾少年们目瞪口呆吗。 如今的各职业大佬回忆起当时情景,无一例外得表示他们的第一反应都是,这公司是骗子吧。 然后一年一次 TI 的传统就延续了下来,除了 TI1,之后的5届都在 Valve 总部西雅图举办,其中中国战队拿了 TI2,TI4,和 TI6的冠军, 去年 TI6 的总奖金更是超过了2000万美元。不论从哪个角度,荣誉还是金钱,把红旗插上西雅图 TI 冠军领奖台都是每个中国战队的终极梦想。

image.png

IG在TI2上首次插旗成功

现在的我看 Dota 比赛比自己玩更有乐趣,主要因素还是水平稀烂吧。除了大学时参加校联赛,关于 Dota 最深刻的记忆还是看比赛: 清楚记得看 TI2 中国战队与国外战队决赛直播时,基友一脸便秘的紧张神情,还有和另一半和基友去 TI5 现场时感受到的盛况空前。 好了,人长大了回忆起来就没完,下面进入正题,聊聊建模的目标: Dota 或者说 MOBA 类游戏可以长盛不衰的魅力就在于英雄的设计,他们各具特色,又相辅相成,不同的英雄给人完全不同的游戏体验。 且我个人认为 Dota2 的英雄设计不管从丰富,独特,还是平衡的角度评判,都是最出众的。 从 TI6 出场英雄数高达105个就可见一斑:现在 Dota2 的英雄总数是113, 除去少数几个当时还不能参加正式联赛的英雄,超过95%的英雄登上了 TI6 的舞台;考虑105取10的组合,这是一个接近3万亿的巨大数字! 所以这次建模,我想纯粹通过英雄选择,来预测比赛胜负。

image.png

TI6现场西雅图Key-Arena

下面正文分三个章节,首先聊聊工具包 RDota2 的使用,这一章在第一次阅读本文时建议快速浏览,了解下都有哪些比赛数据可供提取即可。 然后写如何清洗从 API 抓取到的数据用来建模,第三部分就是建模的步骤和结果了。文章有点长,所以分为上下两篇,第一部分在上篇,二三部分在下篇。等不急想知道哪些英雄对比赛胜负影响最大的老司机,可以先跳到《十行代码预测插旗西雅图(下)》文章末尾一睹为快。

RDota2 简介

在使用 RDota2 之前,我们需要到 “链接1” 申请 Steam API 的 Key。 有 Steam 账号的话马上就能得到。加载 RDota2 之后,只需要设定一次 Key,就能愉快得通过 API 提取数据了。

image.png


当然,更安全的方式是把 Key 存在操作系统的环境变量中,以后引用这个变量即可, 具体流程可以参考 这里。

get_xxx 系列函数

RDota2 通过各种 get 函数连接 Steam API 抓取数据。 所有的 get 函数的返回值都包含三个元素:

  • url: 该次 API 请求的链接,可以把这个链接复制到浏览器的地址栏,回车得到相应的返回值

  • content: 该次 API 请求的具体返回值,因为原始返回数据是 json 格式的,在 R 里面 content 的形式是一个层叠列表

  • response:该次 API 请求在 Steam 服务器里的处理信

除了提取详细比赛信息的函数 get_match_details() 和 get_match_history_by_sequence_num() 之外,这两个函数会在后面具体介绍, 还有以下的函数提取一般比赛和职业联赛的信息:

  • get_event_stats_for_account(eventid, accountid):返回账号 accountid 在一般联赛 eventid 里的记录

  • get_league_listing(): 返回所有联赛的信息

  • get_live_league_games(): 返回正在进行中的联赛以及选手信息

  • get_scheduled_league_games(): 返回已安排的联赛信息

  • get_team_info_by_team_id(start_at_team_id, teams_requested): 从 start_at_team_id 开始提取 teams_requested 个职业战队的信息

  • get_top_live_game(): 返回正在进行中的高水平一般比赛和职业联赛,返回值里面有双方的平均 MMR(战斗力),这也是整个 API 里唯一关联 MMR 的函数

  • get_tournament_player_stats(account_id): 返回账号 account_id 在国际锦标赛 TI 里的记录

  • get_tournament_prize_pool(): 返回国际锦标赛 TI 奖金池状

以下函数可以提取其他的游戏信息:

  • get_game_items(language): 返回所有游戏物品的 data.frame,指定 language 还可以得到物品在这种语言下的名称

  • get_heroes(language): 返回所有 Dota 英雄的 data.frame,指定 language 还可以得到英雄在这种语言下的名称

  • get_item_icon_path(iconname, icontype): 指定物品名称 iconname 和类型 icontype(0=常规,1=大图,3=游戏内),返回物品图标 CDN 地址

  • get_rarities(language): 这个是重点,返回 Dota2 商店内饰品和皮肤的掉落率

image.png

image.png

get_match_details 函数

使用 get_match_details(match_id) 返回比赛详细信息时需要指定该场比赛的 ID,也就是所谓的录像编号。一般比赛会返回一个长度是23的列表, 第1个元素包含了10名玩家的具体游戏信息,它本身也是一个复杂列表,除此之外,其他的元素都是一元的。它们包括:

  • radiant_win: 天辉是否获胜,1=是, 0=否

  • duration: 比赛总时长,以秒计

  • pre_game_duration: 正式比赛前准备时长

  • start_time: 游戏开始时间,Unix 时间形式,下面例子里有时间转化方法

  • match_id: 比赛 ID

  • match_seq_num: 比赛序列号,该编号按比赛开始时间呈次序排列

  • tower_status_radiant: 天辉防御塔状态,具体参考 “链接2”

  • tower_status_dire: 夜魇防御塔状态,具体同上

  • barracks_status_radiant: 天辉兵营状态,具体参考 “链接3”

  • barracks_status_dire: 夜魇兵营塔状态,具体同上

  • first_blood_time: 一血时间

  • lobby_type: 游戏大厅,具体参考 “链接4”,常见的有:

    • 0=公共比赛

    • 1=练习,但所有职业比赛都在这一类里

    • 4=与AI合作/对战,就是所谓的打电脑

    • 7=排位赛,就是所谓的天梯

    • 8=单人比赛,主要用于中路1对1

  • human_players: 非机器人的玩家数量

  • leagueid: 联赛 ID,0=一般比赛

  • positive_votes: “喜欢”投票

  • negative_votes: “不喜欢”投票

  • game_mode: 游戏模式,具体参考 “链接5”,常见的有:

    • 1=全阵营

    • 2=队长模式

    • 3=随机征召

    • 4=个别征召

    • 5=全阵营随机

    • 12=生疏模式

    • 18=随机模型(技能)

    • 20=全阵营死亡模式

    • 21=中路1对1

    • 22=排位全阵营

  • flags: 未知

  • engine: 0=source1, 1=source2

  • radiant_score: 天辉击杀数

  • dire_score: 夜魇击杀数

image.png

image.png

image.png

职业联赛返回列表更长,除了上面的这些信息外,还有两支对决战队的信息,以及列表第34个元素包含的 Ban/Pick 详细信息。 这里取4月亚洲锦标赛的一场决赛为例。祝贺B神!

image.png

image.png

玩家列表(函数返回值的第一个元素)包含10个元素,对应10个玩家,前5个是天辉,后5个是夜魇。 下面是某一个玩家的具体信息,包括所选英雄,物品栏,击杀/死亡/助攻,正反补,金钱经验每分钟,造成伤害/治疗等。第30个元素是关于技能升级的列表。

image.png

image.png

值得注意的是,player_slot 这一栏在设定上是可以区分1到5号位的,但是实际中并没有用到,所以0至4为天辉,128至132为夜魇,玩家按进入游戏次序排列。

┌─────────────── 0=天辉 1=夜魇
│ ┌─┬─┬─┬─────── 没用
│ │ │ │ │ ┌─┬─┬─ 队伍中的1到5号位 (0-4)
0 0 0 0 0 0 0 0

以上就是 get_match_details() 函数的所有返回值。 get_match_history_by_sequence_num(start_at_match_seq_num, matches_requested) 函数的返回值是一模一样的形式, 唯一的不同就是这个函数可以返回多场比赛的详细信息,从 start_at_match_seq_num 开始往后 matches_requested 场比赛, 注意这里必须输入比赛序列号 match_seq_num,该编号按比赛开始时间呈次序排列。另外1次请求最多能返回100场比赛的信息。

image.png

其实还有一个 get 函数 get_match_history(),可以通过输入不同的参数例如 game_mode 来筛选返回的比赛。 但在我测试时,有些输入参数并没有正确的筛选比赛,而且返回的比赛信息太简略,缺少比赛胜负信息,我就没有用这个函数提取比赛数据。 另外插一句,我的文章都发布在统计之都主站(https://cos.name/现转移至https://cosx.org/)和微信公众号。 一些网站会把文章拿过去作为自己的原创内容,这里稍微测试一下,看看他们的小编是直接复制粘贴,还是也稍微编辑一番。

十行代码预测插旗西雅图(下)将继续介绍如何清洗从 API 抓取到的数据用来建模和建模的步骤和结果。

作者简介:侯澄钧,俄亥俄州立大学运筹学博士, 目前在美国从事财产事故险(Property & Casualty)领域的保险产品开发,涉及数据分析、统计建模和产品算法优化等方面的工作。

链接参考:

链接一:

https://steamcommunity.com/login/home/?goto=%2Fdev%2Fapikey

链接二:

https://dota2api.readthedocs.io/en/latest/responses.html#towers-and-barracks

链接三:

https://dota2api.readthedocs.io/en/latest/responses.html#towers-and-barracks

链接四:

https://dota2api.readthedocs.io/en/latest/responses.html#lobby-type

链接五:

https://dota2api.readthedocs.io/en/latest/responses.html#game-mode

推荐 1
本文由 统计之都 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册