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

Python K折交叉验证训练模型时Pandas iloc索引越界报错

问题根因

该iloc越界报错和DataFrame数据缺失无关,是两个开发高频疏漏叠加导致:

  • 第一,KFold切分折内数据后未重置索引:使用df.iloc[train_idx]切分得到的训练/验证子集,会保留原全量DataFrame的全局索引标签,而非从0开始的连续位置索引。iloc是按行位置序号而非索引标签取值,当生成器内从0开始递增的迭代序号超过子集实际行数对应的最大位置时,就会触发越界。

    典型触发场景:全量数据集共1000行,索引范围0999,某折训练集切出900个样本,对应原索引100999。未重置索引的train_df实际行位置范围是0~899,当迭代序号到900时,iloc[900]超出最大位置阈值直接报错,和子集内是否存够样本无关。

  • 第二,每epoch迭代步数计算错误:自定义生成器的__len__方法返回值偏大,或手动给model.fit传入的steps_per_epoch大于折内数据集实际可生成的最大批次数,导致生成器迭代到超出样本总量的序号,触发越界。
修复步骤

按以下顺序修改即可彻底解决:

  1. 切分折内数据后强制重置连续索引
    每次K折切分完成后,对训练、验证子集做索引重置,丢弃原全局索引:
from sklearn.model_selection import KFold
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.applications import ResNet50

kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in kf.split(df):
    # 核心:切分后立刻重置索引,drop=True丢弃原索引列
    train_df = df.iloc[train_idx].reset_index(drop=True)
    val_df = df.iloc[val_idx].reset_index(drop=True)
    # 再将子集传入对应数据生成器
    train_gen = DataGenerator(train_df, batch_size=32)
    val_gen = DataGenerator(val_df, batch_size=32)
    # 模型训练逻辑
  1. 正确实现自定义Sequence生成器的长度计算逻辑
    不要硬编码样本量、不要引用全量数据集长度计算批次数,基于当前传入的子集长度动态计算:
class DataGenerator(tf.keras.utils.Sequence):
    def __init__(self, df, batch_size=32, img_size=(224,224), shuffle=True):
        self.df = df
        self.batch_size = batch_size
        self.img_size = img_size
        self.shuffle = shuffle
        self.n_samples = len(self.df)
        self.on_epoch_end()

    def __len__(self):
        # 向上取整计算总批次数,覆盖最后一个不足batch_size的批次
        return int(np.ceil(self.n_samples / self.batch_size))

    def __getitem__(self, index):
        # 按位置取当前批次的样本索引,不会出现越界
        batch_indices = self.indexes[index*self.batch_size : (index+1)*self.batch_size]
        batch_data = self.df.iloc[batch_indices]
        # 此处补全图像读取、预处理、标签转换的原有逻辑即可
        X = []
        y = []
        for _, row in batch_data.iterrows():
            img = tf.keras.utils.load_img(row['img_path'], target_size=self.img_size)
            img = tf.keras.utils.img_to_array(img)
            X.append(img)
            y.append(row['label'])
        return np.array(X), np.array(y)

    def on_epoch_end(self):
        self.indexes = np.arange(self.n_samples)
        if self.shuffle:
            np.random.shuffle(self.indexes)
  1. 训练时不要手动硬编码迭代步数
    调用model.fit时,直接传入继承了Sequence的生成器实例即可,无需手动指定steps_per_epoch、validation_steps参数,TensorFlow会自动调用生成器的__len__方法获取正确的迭代步数,从根源避免步数算多导致的越界:
model = ResNet50(input_shape=(224,224,3), weights=None, classes=num_classes)
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(
    train_gen,
    validation_data=val_gen,
    epochs=10,
    # 不要手动传steps_per_epoch、validation_steps
)
额外排查项

如果完成上述修改后仍触发同类报错,检查两个细节:

  • 如果生成器内有样本过滤逻辑(比如自动剔除读取失败的损坏图像),过滤完成后必须同步更新self.n_samples和self.indexes的长度,不要保留已剔除样本的索引
  • 不要为了绕开越界把iloc换成loc,该修改会导致位置索引和标签索引错位,最终出现标签和图像不匹配的问题,训练得到的模型完全不可用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:21:22