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

Pandas循环删除DataFrame行后,如何调整迭代范围避免索引越界?

解决Pandas循环遍历并删除行时的索引越界问题

问题场景

初始有一个含12675行的Pandas DataFrame,其info()输出如下:

Proyectonevera2.info()
<class 'pandas.core.frame.DataFrame'>
  Int64Index: 12689 entries, 3 to 12683
   Data columns (total 60 columns):

编写了嵌套循环代码,用于遍历DataFrame、修改数据并删除指定行:

for i in range(0,len(Proyectonevera2)-1):
    if Proyectonevera2.loc[i,'Clave'] == "P":
        CodIng = Proyectonevera2.loc[i,'Ingrediente']
        NuevoInv_Ing = Proyectonevera2.loc[i,'Nuevo Inventario']
        for j in range(0,len(Proyectonevera2)-1):
            if Proyectonevera2.loc[j,'Clave'] == "N":
                Codprod = Proyectonevera2.loc[j,'CodProducto']
                if Proyectonevera2.loc[j,'Ingrediente'] == CodIng:
                    Proyectonevera2.loc[j,'Inv_Ing'] = NuevoInv_Ing
                    if Proyectonevera2.loc[j,'Cant Ingr SUM'] !=0 and Proyectonevera2.loc[j,'Cant Prod SUM']!=0:
                        Proyectonevera2.loc[j,'Cantidad producir']=Proyectonevera2.loc[j,'Inv_Ing']*Proyectonevera2.loc[j,'Cant Prod SUM']/Proyectonevera2.loc[j,'Cant Ingr SUM']
                        dfc = Proyectonevera2.groupby('CodProducto')['Cantidad producir']
                        Proyectonevera2.assign(min=dfc.transform(min))
                        Proyectonevera2.loc[j,'Consumo Agosto'] = Proyectonevera2.loc[j,'min']*Proyectonevera2.loc[j,'Cant Ingr SUM']/Proyectonevera2.loc[j,'Cant Prod SUM']
                        Proyectonevera2.loc[j,'Nuevo Inventario'] = Proyectonevera2.loc[j,'Inv_Ing']-Proyectonevera2.loc[j,'Consumo Agosto']
                        Proyectonevera2= Proyectonevera2.drop(Proyectonevera2[Proyectonevera2['Clave']=="P"].index)
                        Proyectonevera2 = Proyectonevera2.reset_index(drop=True)

执行后触发索引越界报错:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexes\range.py in get_loc(self, key, method, tolerance)
    384                 try:
--> 385                     return self._range.index(new_key)
    386                 except ValueError as err:

ValueError: 12675 is not in range

问题核心:循环基于DataFrame初始长度,但删除行后长度动态缩小,导致后续循环索引超出有效范围。


解决方案

临时调整:基于固定初始索引遍历

如果一定要保留循环逻辑,不要依赖动态变化的len(Proyectonevera2),而是提前获取初始索引列表,遍历固定列表并跳过已删除的索引:

# 提前获取所有初始索引并转为列表(避免迭代时索引动态变化)
initial_indices = list(Proyectonevera2.index)

for idx in initial_indices:
    # 跳过已被删除的索引
    if idx not in Proyectonevera2.index:
        continue
    if Proyectonevera2.loc[idx, 'Clave'] == "P":
        CodIng = Proyectonevera2.loc[idx, 'Ingrediente']
        NuevoInv_Ing = Proyectonevera2.loc[idx, 'Nuevo Inventario']
        
        # 提前获取所有Clave为"N"的初始索引
        n_indices = list(Proyectonevera2[Proyectonevera2['Clave']=="N"].index)
        for j_idx in n_indices:
            if j_idx not in Proyectonevera2.index:
                continue
            if Proyectonevera2.loc[j_idx, 'Ingrediente'] == CodIng:
                Proyectonevera2.loc[j_idx, 'Inv_Ing'] = NuevoInv_Ing
                if Proyectonevera2.loc[j_idx, 'Cant Ingr SUM'] != 0 and Proyectonevera2.loc[j_idx, 'Cant Prod SUM'] != 0:
                    Proyectonevera2.loc[j_idx, 'Cantidad producir'] = (
                        Proyectonevera2.loc[j_idx, 'Inv_Ing'] * Proyectonevera2.loc[j_idx, 'Cant Prod SUM'] 
                        / Proyectonevera2.loc[j_idx, 'Cant Ingr SUM']
                    )
                    # 修正assign的用法:直接赋值列而非返回新DataFrame
                    Proyectonevera2['min'] = Proyectonevera2.groupby('CodProducto')['Cantidad producir'].transform('min')
                    Proyectonevera2.loc[j_idx, 'Consumo Agosto'] = (
                        Proyectonevera2.loc[j_idx, 'min'] * Proyectonevera2.loc[j_idx, 'Cant Ingr SUM'] 
                        / Proyectonevera2.loc[j_idx, 'Cant Prod SUM']
                    )
                    Proyectonevera2.loc[j_idx, 'Nuevo Inventario'] = (
                        Proyectonevera2.loc[j_idx, 'Inv_Ing'] - Proyectonevera2.loc[j_idx, 'Consumo Agosto']
                    )

# 所有处理完成后统一删除P类行,避免循环内频繁修改DataFrame
Proyectonevera2 = Proyectonevera2.drop(Proyectonevera2[Proyectonevera2['Clave']=="P"].index).reset_index(drop=True)

推荐方案:使用Pandas原生向量式操作

Pandas的核心优势是向量式运算,完全不需要嵌套循环,效率更高且彻底避免索引问题:

# 1. 提取P类的Ingrediente与Nuevo Inventario的映射关系
p_mapping = Proyectonevera2[Proyectonevera2['Clave']=="P"].set_index('Ingrediente')['Nuevo Inventario'].to_dict()

# 2. 批量更新N类的Inv_Ing
Proyectonevera2.loc[Proyectonevera2['Clave']=="N", 'Inv_Ing'] = Proyectonevera2.loc[Proyectonevera2['Clave']=="N", 'Ingrediente'].map(p_mapping)

# 3. 定义有效计算的掩码(过滤非零值和N类行)
mask = (Proyectonevera2['Cant Ingr SUM'] != 0) & (Proyectonevera2['Cant Prod SUM'] != 0) & (Proyectonevera2['Clave']=="N")

# 4. 批量计算Cantidad producir
Proyectonevera2.loc[mask, 'Cantidad producir'] = (
    Proyectonevera2.loc[mask, 'Inv_Ing'] * Proyectonevera2.loc[mask, 'Cant Prod SUM'] 
    / Proyectonevera2.loc[mask, 'Cant Ingr SUM']
)

# 5. 分组计算min值
Proyectonevera2['min'] = Proyectonevera2.groupby('CodProducto')['Cantidad producir'].transform('min')

# 6. 批量计算Consumo Agosto和Nuevo Inventario
Proyectonevera2.loc[mask, 'Consumo Agosto'] = (
    Proyectonevera2.loc[mask, 'min'] * Proyectonevera2.loc[mask, 'Cant Ingr SUM'] 
    / Proyectonevera2.loc[mask, 'Cant Prod SUM']
)
Proyectonevera2.loc[mask, 'Nuevo Inventario'] = Proyectonevera2.loc[mask, 'Inv_Ing'] - Proyectonevera2.loc[mask, 'Consumo Agosto']

# 7. 最后统一删除P类行
Proyectonevera2 = Proyectonevera2[Proyectonevera2['Clave']!="P"].reset_index(drop=True)

关键优化说明

  • 避免循环内删除行:统一在所有数据处理完成后删除指定行,减少DataFrame的动态变更
  • 替换嵌套循环为向量操作:运算速度提升数倍至数十倍,彻底规避索引越界风险
  • 修正assign用法:assign返回新DataFrame,不会修改原数据,需直接对列赋值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 21:39:20