用Python和pandas量化英雄联盟战队BP表现:从数据清洗到可视化分析
发布时间:2026/9/4 3:09:04 锦皓数字建站

又到了复盘比赛内容的时候。每次聊到 VIT弹幕里总能看到类似“VIT 的 BP 正在进步”“Fiesta 打得很有冒险精神”“队内气氛好像不错”这样的评论。这些说法听起来主观但如果把问题剥开其实是可以用数据去验证的队伍在蓝色方和红色方各拿什么英雄前两手是不是永远锁同一套版本热门英雄被 Ban 之后有没有备用方案连续几场失利之后BP 优先级有没有出现方向性的调整与其凭印象争论一支战队的 BP 到底进步没有不如自己动手写一套小脚本把比赛数据拉下来、清洗、统计、可视化用最终的图表说话。这篇文章就围绕“英雄联盟战队 BP 数据分析”这个方向展开。不需要很重的框架Python pandas matplotlib 就能完成。无论你是想分析 LEC 的 VIT还是想分析自己参与的业余联赛这套思路都可以直接复用。阅读本文你会得到三样东西一是看懂比赛 BP 数据结构的基本方法二是完整可运行的 Python 分析代码三是一套判断“ BP 是否正在变好”的量化思路而不是只盯着比分牌说话。1. 为什么要量化战队的 BP 表现英雄联盟比赛里的 BPBan/Pick是赛前博弈最重要的环节。Ban 掉什么英雄通常取决于版本强度、选手英雄池、对手惯用体系以及红蓝方的博弈策略。Pick 什么英雄则决定了一支队伍在游戏前中后期的节奏模型。一支战队的 BP 水平很难从单场比赛直接判断。举个例子某一场比赛里 VIT 在蓝色方一抢了强势上单解说夸这个 BP 做得舒服但下一场比赛对手同样在蓝色方一抢了同一个英雄VIT 应对得却很差。这时候我们就会发现单独看一两场比赛的“感觉”并不可靠必须把一段时间内的 BP 采样放在一起看。量化 BP 表现有几个非常直接的好处可以区分“选手个人发挥好”和“BP 本身好”。如果一套阵容选出来线上打出了巨大优势那是选手状态问题如果每场都是逆版本选人前期没有任何主动性那就值得怀疑 BP 是不是拖了后腿。可以判断 BP 是否真的在调整。通过对比队伍前 10 场的英雄优先级和后 10 场的变化就能验证“进步”到底是客观事实还是赛后采访里的客套话。可以发现队伍的英雄池短板。某个版本热门英雄在对面永远不 Ban 也不抢那大概率是这个英雄不在本方体系里或者选手根本不玩。换句话说BP 分析就是一支队伍赛训策略的“体检报告”。与其只看结果不如把选人逻辑拆开。2. 环境准备与数据说明本文以 Python 为主要工具。需要的类库不复杂核心是三个pandas负责数据清洗和聚合统计是分析阶段最常用的工具。matplotlib负责画图生成趋势图、频率柱状图。numpy辅助计算和数组操作某些统计场景会用到。建议先创建一个独立的项目目录避免脚本文件散落各处。mkdir lol-bp-analysis cd lol-bp-analysis python -m venv venvWindows 系统激活虚拟环境venv\Scripts\activatemacOS / Linux 系统激活虚拟环境source venv/bin/activate然后安装依赖pip install pandas matplotlib numpy关于版本我的建议是不必追求最新。只要 pandas 和 matplotlib 能正常导入并且支持 DataFrame 的基本操作教学示例就可以顺利执行。如果你在本机已经安装了 Anaconda前面的步骤可以省略直接用 Jupyter Notebook 跟着写即可。接下来是数据问题。英雄联盟赛事数据的获取渠道比较多常见方式包括官方赛事 API、第三方电竞数据平台、开发者社区维护的数据集。不同渠道的数据字段和更新频率存在差异而且 API 的访问权限和调用规则经常调整所以我在这篇教程里不写死某个接口的调用方式而是先构造一份和真实赛事数据格式非常接近的本地 CSV 数据用这份数据跑通分析流程。等流程通了你需要做的只是把自己获取到的真实数据替换进 CSV 文件即可。这种方式最大的好处是稳定无论外界 API 怎么变化分析代码的核心逻辑不会受影响。3. 读懂 BP 数据从一局比赛到一张数据表在写代码之前先建立几个基本概念。一场比赛在正式进入对局之前会经历 BP 阶段。首先是 Ban 人阶段一般分为三轮总计每方 5 个 Ban 位然后是 Pick 阶段双方交错选人最终每方选出 5 个英雄。BP 完成后进入召唤师峡谷。如果我们要量化分析就不能只把 BP 当作一段无法保存的直播画面而需要把这场博弈转写成结构化数据。常见的最小数据粒度是一行代表一个英雄事件。这里有两个方案方案 A一行记录代表一支战队在某场比赛里的完整 BP。字段可能是match_id比赛编号team战队名side蓝色方 / 红色方ban_1 到 ban_55 个被 Ban 的英雄pick_1 到 pick_55 个被选出的英雄result本场比赛胜负方案 B一行记录代表一次 Ban 或一次 Pick。字段可能是match_id比赛编号team战队名side蓝色方 / 红色方actionban / pickchampion英雄名order第几个执行result比赛胜负方案 B 是“长表”每个行为单位很适合用 pandas 做 groupby 聚合也更容易计算某个英雄的 Ban 率、Pick 率、胜率。因此本文选择方案 B 作为核心数据结构。下面我们模拟一份示例数据。这里的队伍名称使用“TeamA”“TeamB”英雄名使用贴近真实风格的英文名比如“Azir”“LeeSin”。实际分析 VIT 或 Fiesta 时你只需要把真实比赛数据替换进来即可。为了让你快速理解数据长什么样可以先看下面的 Python 构造逻辑。import pandas as pd import numpy as np rows [] # 模拟 20 场 VIT 相关比赛 np.random.seed(42) team_names [VIT, TeamA, TeamB, TeamC] champions_pool [ Azir, LeeSin, Ornn, KaiSa, Thresh, Rakan, Gnar, Syndra, Taliyah, Aphelios, Nautilus, Elise, Camille, Lucian, Renata, Vi, Yone, Jinx, Leona, Aatrox ] # 构造约 700 行 BP 事件数据 for game in range(20): for team_index, team in enumerate([VIT, TeamA]): side blue if team_index 0 else red result 1 if (game team_index) % 2 0 else 0 # 每队 5 个 ban 和 5 个 pick for order in range(5): rows.append({ match_id: fGAME_{game1:03d}, team: team, side: side, action: ban, champion: np.random.choice(champions_pool), order: order 1, result: result }) for order in range(5): rows.append({ match_id: fGAME_{game1:03d}, team: team, side: side, action: pick, champion: np.random.choice(champions_pool), order: order 1, result: result }) df pd.DataFrame(rows) print(df.head()) print(df.shape)执行上面的代码你会看到一个包含约 700 行的 DataFrame。其中前几行大概是match_id team side action champion order result 0 GAME_001 VIT blue ban Vi 1 1 1 GAME_001 VIT blue ban Rakan 2 1 ...这只是一份演示数据它的随机性不代表任何真实赛况。它的作用是方便后续代码运行。4. 核心代码实现统计 VIT 的 BP 风格当我们拿到了格式规整的数据后第一步不是画图而是先完成几个基础统计。4.1 计算 Ban / Pick 频率Ban 率反映的是“这个英雄值得被尊敬的程度”。Pick 率反映的是“队伍主动选择该英雄的频率”。如果某英雄的 Pick 率非常高说明它有可能是这支队伍的核心体系英雄。def calc_frequency(df, team_name, action_type): team_df df[(df[team] team_name) (df[action] action_type)] total len(team_df) freq ( team_df.groupby(champion) .size() .reset_index(namecount) ) freq[freq] freq[count] / total freq freq.sort_values(freq, ascendingFalse).reset_index(dropTrue) return freq vit_pick_freq calc_frequency(df, VIT, pick) print(vit_pick_freq.head(10))这部分输出的含义是在 VIT 所有 Pick 行为中哪些英雄出现占比最高。比如某英雄占比 0.08意味着 VIT 每 100 次选人里大约有 8 次会选到这个英雄。这里需要注意一个细节如果样本量很小比如只有 5 场比赛那么每队总共只有 25 个 Pick 事件频率结果会很不稳定一分钟一个版本。实际分析时要先确认样本量足够最好至少累计 10 场以上。4.2 统计英雄胜率只看 Pick 频率还不够。如果队伍经常选某个英雄但这个英雄胜率很低说明这个选择可能存在“舒适区陷阱”选手爱玩但赢不了。def calc_win_rate(df, team_name, action_typepick): team_df df[(df[team] team_name) (df[action] action_type)] stats ( team_df.groupby(champion)[result] .agg(countcount, win_sumsum) .reset_index() ) stats[win_rate] stats[win_sum] / stats[count] stats stats[stats[count] 3].sort_values(win_rate, ascendingFalse) return stats vit_pick_stats calc_win_rate(df, VIT) print(vit_pick_stats.head(10))这里我设置了count 3的过滤条件。原因是如果某个英雄只出现了 1 次胜率只有 0% 或 100%这种数据没有统计意义。实际项目中这个阈值可以根据赛事场次调整比赛场次更多时建议把阈值提高到 5 次以上。4.3 区分红蓝方的 BP 差异职业比赛里红色方通常需要承担更多 Ban 位压力因为蓝色方有一抢权。因此分析 BP 时把红蓝方混在一起会掩盖很多细节。def calc_side_freq(df, team_name, action_typepick): team_df df[(df[team] team_name) (df[action] action_type)] side_stats ( team_df.groupby([side, champion]) .size() .reset_index(namecount) ) total team_df.groupby(side).size().reset_index(nametotal) side_stats side_stats.merge(total, onside) side_stats[freq] side_stats[count] / side_stats[total] side_stats side_stats.sort_values([side, freq], ascending[True, False]) return side_stats vit_side_pick calc_side_freq(df, VIT, pick) print(vit_side_pick.head(10))这组数据如果做出来之后发现VIT 在蓝色方经常一抢某个打野而红色方几乎不选同一个打野那么红色方的 BP 分析就值得单独往下挖了。5. 用可视化和“前后期对比”验证 VIT 的 BP 是否在进步统计完频率和胜率后我们会得到一堆静态结果但它还不能回答“BP 正在进步”这个问题。因为“进步”是一个动态概念需要一个时间维度的对比。最简单的办法是把 VIT 的比赛按时间分成前 N 场和后 N 场对比两者在英雄选择、胜负、不同位置 Pick 率上的差异。如果窗口足够大也可以使用滚动平均。5.1 按比赛顺序对比两个阶段我们为 DataFrame 增加一个简单的序号用于表示比赛先后。df[game_order] df[match_id].str.extract(r(\d)).astype(int)接着把整支队伍的比赛切分成前半段和后半段。game_count df.drop_duplicates(match_id)[match_id].count() split_point game_count // 2 df[period] df[game_order].apply( lambda x: latter if x split_point else former ) vit_df df[df[team] VIT].copy() former_pick vit_df[(vit_df[period] former) (vit_df[action] pick)] latter_pick vit_df[(vit_df[period] latter) (vit_df[action] pick)] former_win_rate former_pick[result].mean() latter_win_rate latter_pick[result].mean() print(前半段胜率:, former_win_rate) print(后半段胜率:, latter_win_rate)这里的胜率是按“BP 事件对应比赛结果”计算的。每场比赛的胜负会同时作用于该场比赛中的 5 个 Pick 事件因此在统计时要明白某一个英雄胜率更高并不完全等于这个英雄带飞了比赛它也可能只是说明队伍在选出这套阵容时整体状态更好。这其实是一个很常见的误区把 BP 胜率理解成了英雄 solo 胜率。在比赛数据中选人阶段只是游戏的第一步后续的战术执行、选手发挥同样会作用于比赛结果。5.2 绘制英雄选择频率的变化图画图可以帮助我们直观感受一个阶段的变化。下面的代码统计 VIT 前半段和后半段 Pick 次数前 8 的英雄并做可视化对比。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, Arial Unicode MS] plt.rcParams[axes.unicode_minus] False def top_n_freq(pick_df, n8): total len(pick_df) freq pick_df.groupby(champion).size().reset_index(namecount) freq[freq] freq[count] / total return freq.sort_values(freq, ascendingFalse).head(n) former_top top_n_freq(former_pick) latter_top top_n_freq(latter_pick) fig, axes plt.subplots(1, 2, figsize(12, 5)) formers dict(zip(former_top[champion], former_top[freq])) laters dict(zip(latter_top[champion], latter_top[freq])) all_champs list(dict.fromkeys( list(formers.keys()) list(laters.keys()) )) former_vals [formers.get(c, 0) for c in all_champs] latter_vals [laters.get(c, 0) for c in all_champs] axes[0].barh(all_champs, former_vals, color#4C72B0) axes[0].set_title(VIT former period pick freq) axes[1].barh(all_champs, latter_vals, color#DD8452) axes[1].set_title(VIT latter period pick freq) plt.tight_layout() plt.savefig(vit_period_pick_compare.png, dpi150) plt.show()图表的作用不是让文章变复杂而是让你在看到“后半段蓝色柱子明显变短”“某个英雄从列表顶端消失”的一瞬间找到 BP 改变最明显的证据。例如如果某位以“冒险精神”著称的打野选手前半段经常选出螳螂、豹女这类高风险的野核英雄而后半段突然开始频繁拿猪妹、大树这种工具人打野那这个变化未必是退步也可能是教练组根据当前版本重新定义了阵容核心。6. 用事件序列拆解队伍的“关键调整能力”比统计更高级的分析方向是观察队伍在失利之后如何调整 BP。这在赛训里有更实际的价值。毕竟一支队伍 BP 是不是在进步最核心的判断指标不是简单的胜率而是“自我修正速度”。一个可操作的量化方法是把连续失利的比赛找出来看下一场比赛中BP 阶段发生了哪些变化。具体可以看三点一上一场输掉的阵容中是否有英雄在下一场直接被 Ban 掉或不再优先 Pick。这说明教练组意识到某个选角无效并及时止损。二上一场的蓝色方首抢位置是否调整。如果第一局蓝色方一抢输出型英雄但被对手节奏碾压下一场改成先抢节奏型打野或强势辅助说明教练组的优先级思路发生了变化。三上一场被对手限制的关键点是否在下一场主动 Ban 掉。这是一种反向学习也就是从失败中获知对手的核心打法并在下次交锋前做出响应。下面的代码可以演示如何找出“位于失利场次之后的首选英雄变化”。# 找出 VIT 失利的比赛 lose_games ( vit_df[vit_df[action] pick] .groupby(match_id)[result] .max() .reset_index() ) lose_games lose_games[lose_games[result] 0][match_id].tolist() # 为下一场比赛设置一个前驱场次标识 vit_df[next_game_flag] vit_df[match_id].map( lambda x: fGAME_{int(x.split(_)[1]) 1:03d} )真实分析时这里还要考虑不同比赛日、不同版本之间的间隔。如果两场比赛间隔数周中间游戏版本更新过那 BP 变化就不能全部归因于队伍修正很可能是版本把某些英雄推下了舞台。因此做赛训归因时一定要记录数据对应的游戏版本号。没有版本信息就很难把“队伍变强”和“版本红利”分开。7. 常见问题与排查思路在跑这份分析脚本时新手大概率会遇到下面几个问题。问题现象常见原因解决思路导入中文标签时图形出现方块matplotlib 默认字体不含中文字符设置plt.rcParams[font.sans-serif]比如 SimHei 或 Microsoft YaHeiLinux 服务器可安装文泉驿字体统计出来的英雄名大小写不统一不同来源的数据没有清洗干净分析前统一转小写或统一首字母大写并对同一英雄的多别名做映射某英雄胜率异常高或低样本量太少增加count 3或count 5的过滤条件前后半段对比结果没有差异比赛场次太少或者切分点不合理改成滚动窗口分析每 5 场计算一次移动平均分析结果与真实观赛感受不一致数据只反映 BP不反映选手操作结合比赛内的首杀、一塔、小龙控制率做联合分析出现第一个问题时可以先检查运行环境中的可用字体再执行import matplotlib.font_manager as fm fonts [f.name for f in fm.fontManager.ttflist if Hei in f.name or Yai in f.name] print(fonts)如果输出为空说明当前环境没有合适的中文字体需要先安装。这些问题的解决思路都是通用的不依赖具体客户端或网站。8. 数据分析落到赛训建议时的工程实践数据分析并不是跑完代码就结束了。从代码到“能指导队伍 BP 优化”的结论之间还隔着非常重要的工程规范。这里整理几个我在实际分析电竞数据时比较重视的要点。第一点是数据字段的标准化。不管是自己手工录的数据还是写爬虫抓取的数据入库前都要先统一字段。champion 不要一会叫 “LeeSin” 一会叫 “lee sin”match_id 不要一会是数字一会又是字符串更不能出现一行的 side 写成 “blue” 而另一行写成 “Blue” 的情况。前期不花时间清洗后期所有统计都会受影响。第二点是版本信息的记录。英雄联盟职业比赛和游戏版本高度绑定。分析结果要在版本大更新之后及时重置。我自己一般会在每份导出数据里增加patch字段并定期对版本号做一次校验。第三点是样本量意识。分析战队 BP 时人的直觉经常会被最近一两场极端对局带偏。例如 Fiesta 某场选出盲僧踢出精彩操作观众会习惯性认为“VIT 的 BP 鼓励高风险操作”但回过头看过去 10 场数据也许盲僧只出场了一次。为了避免这类偏误我通常会先打印一个总体样本量再决定结论的置信程度。第四点是不把单个指标神化。BP 分析中常用的 Pick 率、Ban 率、胜率终究是简化指标。它们无法精准反映“指挥型辅助的带动作用”或“某个英雄面对特定 Counter 关系的隐性收益”。因此数据报告里不要只堆指标而是要回到比赛内容去理解异常点。第五点是安全问题。在获取赛事数据时原则上应该优先使用官方渠道和获准的公开数据源不要使用未经授权、包含恶意脚本的爬虫包。如果你的本地爬虫触发了网站的反爬机制应当立刻停止并及时联系数据提供方而不是继续做高频率请求。电竞数据分析是辅助赛训和看比赛的工具前提是合法合规、不破坏目标站点。9. 更进一步从 BP 数据入口建立自己的赛训观察面板到这里一套基于 Python 的 BP 数据分析链路已经跑通了。我们真正完成的不只是数一数英雄出现次数而是建立了一个能回答“VIT 的 BP 正在进步吗”这一类问题的分析框架。当然这个框架还有很多可以延伸的方向。例如引入比赛内前 15 分钟的领先数据来判断阵容前期强度结合选手个人排位记录来预测英雄池变化或者抓取游戏版本改动公告把英雄补丁和队伍 BP 优先级放在同一张时间轴上。数据分析在这里最大的价值不是取代教练组和选手的判断而是把模糊的赛训感觉转化为可追溯的记录。哪怕今天只是分析了自己主队最近 5 场的小数据也会对 BP 背后的逻辑有新的理解。看过图表之后如果能发现一个“原来这套阵容在某个侧路选出来胜率这么低”的瞬间这篇教程就没有白写了。我自己一般在跑完一次完整分析后会把脚本固定成三种模式单队伍 BP 总览、红蓝方差异对比、失利后调整响应。日常赛训只维护这三种图表数据量小产出也稳定。你需要时可以顺着这个思路继续往下做把它扩展成适合自己主队的观察面板。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。