You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas IndexError: index 0 is out of bounds问题排查求助

Elo评分算法代码IndexError错误排查

问题描述

运行基于Elo评分的Python代码时触发IndexError: index 0 is out of bounds for axis 0 with size 0,错误发生在获取球队上一场比赛Elo评分的逻辑中。

数据信息

game_info.info()

输出:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 30362 entries, 0 to 30361
Data columns (total 10 columns):
 #   Column         Non-Null Count  Dtype         
---  ------         --------------  -----         
 0   competitionId  30362 non-null  Int64         
 1   gameId         30349 non-null  Int64         
 2   gameDate       30362 non-null  datetime64[ns]
 3   gameTime       30362 non-null  datetime64[ns]
 4   awayId         30362 non-null  int64         
 5   homeId         30362 non-null  int64         
 6   awayScore      30362 non-null  int64         
 7   homeScore      30362 non-null  int64         
 8   homeWin        29889 non-null  Int64         
 9   homePush       30362 non-null  Int64         
dtypes: Int64(4), datetime64[ns](2), int64(4)
memory usage: 2.4 MB

game_info.head()结果:

competitionIdgameIdgameDategameTimeawayIdhomeIdawayScorehomeScorehomeWinhomePush
0202145847622022-01-202022-01-20 20:00:00765829755600
1202145864202022-01-082022-01-08 15:00:00823677686600
2201836421552019-01-242019-01-24 18:00:001374670708810
3202146112862022-01-102022-01-10 19:30:00825824589510
4202246781822022-12-292022-12-29 19:00:001099824549210

代码

Elo计算函数

# 获取主队预期胜率
def get_home_E(homeElo, awayElo): 
    home_win_prob = 1./(1 + 10 ** ((awayElo - homeElo) / (400)))
    return home_win_prob

# 获取K值乘数
def get_k(MOV, elo_diff): 
    k_initial = 20 
    if MOV > 0: 
        multiplier = (MOV + 3)**0.8 / (7.5 + 0.006 * (elo_diff))
    else: 
        multiplier = (-MOV + 3)**0.8 / (7.5 + 0.006 * (-elo_diff))
    return k_initial * multiplier 

# 更新Elo评分
def update_elo(homeScore, awayScore, homeEloPrev, awayEloPrev):
    home_adv = 100 
    homeElo = homeEloPrev + home_adv 
    home_E = get_home_E(homeElo, awayEloPrev) 
    elo_diff = homeEloPrev - awayEloPrev
    MOV = homeScore - awayScore 
    if (MOV > 0) :
        home_S = 1 
    elif (MOV < 0):
        home_S= 0 
    else: 
        home_S = 0.5 
    
    k = get_k(MOV, elo_diff)
    home_elo_update = k * (home_S - home_E) 

    updated_home_elo = homeEloPrev + home_elo_update
    updated_away_elo = awayEloPrev - home_elo_update

    return updated_home_elo, updated_away_elo

# 获取球队上一场比赛后的Elo评分
def get_prev_elo(teamId, gameTime, competitionId, game_info, elo_per_game): 
    prev_game = game_info[game_info['gameTime'] < gameTime][((game_info['homeId'] == teamId) | (game_info['awayId'] == teamId)) & (game_info['gameId'] != gameId)].tail(1).iloc[0]
    if teamId == prev_game['homeId'] :
        elo_rating = elo_per_game[elo_per_game['gameId'] == prev_game['gameId']]['homeEloAfter'].values[0]
    else:
        elo_rating = elo_per_game[elo_per_game['gameId'] == prev_game['gameId']]['awayEloAfter'].values[0]

    if prev_game['competitionId'] != competitionId :
        return (0.75 * elo_rating) + (0.25 * 1505)
    else:
        return elo_rating

主循环代码

# 存储每局比赛的Elo结果
elo_per_game = pd.DataFrame(columns=['competitionId', 'gameId', 'gameDate', 'homeId', 'awayId', 'homeEloPrev', 'awayEloPrev', 'homeEloAfter', 'awayEloAfter'])
elo_per_team = pd.DataFrame(columns=['competitionId', 'gameId', 'gameDate', 'teamId', 'elo', 'home']) 

for index, row in game_info.iterrows():
    # 提取当前比赛信息
    gameId = row['gameId'] 
    competitionId = row['competitionId']
    gameDate = row['gameDate'] 
    gameTime = row['gameTime'] 
    homeId, awayId = int(row['homeId']), int(row['awayId'])
    homeScore, awayScore = row['homeScore'], row['awayScore']
    
    # 获取主队上一场Elo(首次比赛用1500)
    if (homeId not in elo_per_game['homeId'].values and homeId not in elo_per_game['awayId'].values): 
        homeEloPrev = 1500
    else: 
        homeEloPrev = get_prev_elo(homeId, gameTime, competitionId, game_info, elo_per_game)
        
    # 获取客队上一场Elo(首次比赛用1500)
    if (awayId not in elo_per_game['homeId'].values and awayId not in elo_per_game['awayId'].values): 
        awayEloPrev = 1500 
    else: 
        awayEloPrev = get_prev_elo(awayId, gameTime, competitionId, game_info, elo_per_game)
    
    # 更新当前比赛的Elo评分
    homeEloAfter, awayEloAfter = update_elo(homeScore, awayScore, homeEloPrev, awayEloPrev) 

    # 将结果写入数据框
    updated_row = {
        'gameId': gameId,
        'competitionId': competitionId,
        'gameDate': gameDate,
        'homeId': homeId,
        'awayId': awayId,
        'homeEloPrev': homeEloPrev,
        'awayEloPrev': awayEloPrev, 
        'homeEloAfter' : homeEloAfter,
        'awayEloAfter': awayEloAfter
    }
    elo_per_game = elo_per_game.append(updated_row, ignore_index = True)

    homeTeam = {'gameId': gameId, 'competitionId': competitionId, 'gameDate': gameDate, 'teamId': homeId, 'elo': homeEloPrev, 'home': True}
    awayTeam = {'gameId': gameId, 'competitionId': competitionId, 'gameDate': gameDate, 'teamId': awayId, 'elo': awayEloPrev, 'home': False}
    elo_per_team = elo_per_team.append(homeTeam, ignore_index = True)
    elo_per_team = elo_per_team.append(awayTeam, ignore_index = True)
    
    # 每处理4000条记录打印日志
    if index % 4000 == 0:
        print(index)

错误信息

--------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[713], line 17
     15     homeEloPrev = 1500
     16 else: 
---> 17     homeEloPrev = get_prev_elo(homeId, gameTime, competitionId, game_info, elo_per_game)
     19 # grab away teams previous ELO (1500 if first game) 
     20 if (awayId not in elo_per_game['homeId'].values and awayId not in elo_per_game['awayId'].values): 

Cell In[712], line 44, in get_prev_elo(teamId, gameTime, competitionId, game_info, elo_per_game)
     42     elo_rating = elo_per_game[elo_per_game['gameId'] == prev_game['gameId']]['homeEloAfter'].values[0]
     43 else:
---> 44     elo_rating = elo_per_game[elo_per_game['gameId'] == prev_game['gameId']]['awayEloAfter'].values[0]
     46 if prev_game['competitionId'] != competitionId :
     47     return (0.75 * elo_rating) + (0.25 * 1505)

IndexError: index 0 is out of bounds for axis 0 with size 0

错误原因分析

  1. 游戏处理顺序错误:game_info中的比赛未按gameTime升序排列(比如第0行比赛时间晚于第1行),主循环按原DataFrame索引顺序处理时,会先处理时间较晚的比赛,此时该球队之前的更早比赛还未被处理,elo_per_game中没有对应记录,导致查找失败。
  2. get_prev_elo函数参数缺失:函数中使用了gameId变量,但未将其作为参数传入,会意外引用主循环中的当前gameId,可能导致筛选逻辑错误。
  3. 链式索引与安全访问缺失:直接使用.iloc[0]和.values[0]访问数据,未判断结果是否为空,一旦找不到对应记录就会触发索引错误。

修复方案

1. 先按比赛时间排序game_info

确保处理顺序从最早到最晚,这样处理当前比赛时,球队之前的比赛已经被处理并写入elo_per_game:

# 按gameTime升序排序,确保处理顺序正确
game_info = game_info.sort_values('gameTime').reset_index(drop=True)

2. 修复get_prev_elo函数参数与逻辑

加入current_gameId参数,优化筛选逻辑,并增加空值判断:

def get_prev_elo(teamId, gameTime, competitionId, current_gameId, game_info, elo_per_game): 
    # 筛选该球队参与的、时间早于当前比赛的所有记录
    team_games = game_info[
        ((game_info['homeId'] == teamId) | (game_info['awayId'] == teamId)) &
        (game_info['gameTime'] < gameTime) &
        (game_info['gameId'] != current_gameId)
    ]
    # 如果没有找到之前的比赛,返回初始值1500
    if team_games.empty:
        return 1500
    # 取最近的一场比赛
    prev_game = team_games.sort_values('gameTime').iloc[-1]
    # 查找该比赛的Elo记录
    prev_game_elo = elo_per_game[elo_per_game['gameId'] == prev_game['gameId']]
    if prev_game_elo.empty:
        return 1500
    # 获取对应球队的Elo评分
    if teamId == prev_game['homeId'] :
        elo_rating = prev_game_elo['homeEloAfter'].iloc[0]
    else:
        elo_rating = prev_game_elo['awayEloAfter'].iloc[0]
    # 跨赛事Elo调整
    if prev_game['competitionId'] != competitionId :
        return (0.75 * elo_rating) + (0.25 * 1505)
    else:
        return elo_rating

3. 修改主循环中调用get_prev_elo的代码

传入current_gameId参数:

# 获取主队上一场Elo
if (homeId not in elo_per_game['homeId'].values and homeId not in elo_per_game['awayId'].values): 
    homeEloPrev = 1500
else: 
    homeEloPrev = get_prev_elo(homeId, gameTime, competitionId, gameId, game_info, elo_per_game)
    
# 获取客队上一场Elo
if (awayId not in elo_per_game['homeId'].values and awayId not in elo_per_game['awayId'].values): 
    awayEloPrev = 1500 
else: 
    awayEloPrev = get_prev_elo(awayId, gameTime, competitionId, gameId, game_info, elo_per_game)

4. 优化数据查找效率(可选)

为elo_per_game的gameId列建立索引,加快查找速度:

elo_per_game = pd.DataFrame(columns=['competitionId', 'gameId', 'gameDate', 'homeId', 'awayId', 'homeEloPrev', 'awayEloPrev', 'homeEloAfter', 'awayEloAfter'])
elo_per_game.set_index('gameId', inplace=True)
# 写入时修改为.loc方式
elo_per_game.loc[gameId] = updated_row
# 查找时直接用索引
prev_game_elo = elo_per_game.loc[prev_game['gameId']]

验证修复

完成上述修改后,重新运行代码,应该不会再触发IndexError。可以在get_prev_elo中加入打印语句,验证找到的prev_game和对应的Elo记录是否正确。

内容的提问来源于stack exchange,提问作者Tim R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 13:37:03