多人游戏类ELO评分系统:优化Python代码提升运行速度
问题描述
我正在为在线游戏玩家开发类ELO评分系统,ELO原本适用于一对一游戏,现在需要适配多人游戏场景。我用指数函数调整序值范围,给获胜者和名次接近的玩家更高权重。数据里,事件包含event_id(事件ID)和fsize(参赛人数)字段,玩家包含player_id(玩家ID)和finish(名次)字段。当前代码运行结果合理,但处理10万量级的事件数据时速度太慢,希望得到代码优化的帮助。
示例数据集
data_dict = {'event_id': [1,1,1,2,2,2,3,3,3,3,4,4,4,4,4], 'player_id': [1,2,3,1,2,3,1,2,3,4,1,2,3,4,5], 'fsize': [3,3,3,3,3,3,4,4,4,4,5,5,5,5,5], 'finish': [1,2,3,1,2,3,1,2,3,4,1,2,3,4,5]} df = pd.DataFrame(data_dict) base = 1.5 # 指数分数的底数,需大于1 # n 是事件中的参赛人数 # 示例:底数1.5、n=3时的指数分数 # np.array([base ** (n - p) - 1 for p in range(1, n + 1)])[0] print(np.array([base ** (5 - p) - 1 for p in range(1, 5 + 1)])[0]) print(np.array([base ** (5 - p) - 1 for p in range(1, 5 + 1)])[1]) print(np.array([base ** (5 - p) - 1 for p in range(1, 5 + 1)])[2]) # pd.set_option('mode.chained_assignment', None) df['score'] = 0 # 初始化分数列 for j in range(0, df.shape[0]): df['score'][j] = np.array([base ** (df['fsize'][j] - p) - 1 for p in range(1, df['fsize'][j] + 1)])[df['finish'][j]-1] # 归一化分数,使每个event_id下的score总和为1 df['score_sum'] = df['score'].groupby(df['event_id']).transform('sum') df['score_norm'] = round(df.score/df['score_sum'],4) print(df)
优化后的代码
import pandas as pd import numpy as np data_dict = {'event_id': [1,1,1,2,2,2,3,3,3,3,4,4,4,4,4], 'player_id': [1,2,3,1,2,3,1,2,3,4,1,2,3,4,5], 'fsize': [3,3,3,3,3,3,4,4,4,4,5,5,5,5,5], 'finish': [1,2,3,1,2,3,1,2,3,4,1,2,3,4,5]} df = pd.DataFrame(data_dict) base = 1.5 # 向量化计算score:直接计算每个玩家对应的指数值,无需生成完整数组再索引 df['score'] = base ** (df['fsize'] - df['finish']) - 1 # 按event_id分组求和,用transform广播到每行 df['score_sum'] = df.groupby('event_id')['score'].transform('sum') # 归一化并保留4位小数 df['score_norm'] = df['score'] / df['score_sum'] df['score_norm'] = df['score_norm'].round(4) print(df)
优化说明
- 向量化替代循环:原代码逐行生成数组再取索引,现在直接利用pandas的列运算,对所有行一次性计算
score,速度提升几个数量级。 - 减少重复计算:原循环里每次都重新计算
score_sum,现在只在score计算完成后做一次分组求和,避免冗余操作。 - 避免链式赋值问题:原代码中
df['score'][j]属于链式赋值,可能引发警告或意外行为,优化后直接列赋值更安全高效。
内容的提问来源于stack exchange,提问作者cousin_pete
相关产品推荐
相关产品推荐

