多列DataFrame处理连续1计数触发KeyError:-1的原因与解决方法
DataFrame连续1转递增数值的实现问题
需求说明
需将DataFrame中连续的1转换为递增数值(连续的1依次变为1、2、3…,0保持不变),示例如下:
输入DataFrame
print(df) Out[1]: Numbers 0 0 1 1 2 1 3 1 4 1 5 0 6 0 7 1 8 0 9 1 10 1
期望输出
print(dfo) Out[2]: Numbers 0 0 1 1 2 2 3 3 4 4 5 0 6 0 7 1 8 0 9 1 10 2
当前问题
通过嵌套循环结合loc判断逻辑实现时,单列DataFrame可正常运行,但扩展至多列DataFrame时触发KeyError: -1,报错信息如下:
File "C:\Users\talls\.conda\envs\Spyder\lib\site-packages\pandas\core\indexes\range.py", line 393, in get_loc raise KeyError(key) from err KeyError: -1
问题解答
1. 错误产生的原因
核心问题是**loc是标签索引,而默认RangeIndex(行索引从0开始)不支持-1作为标签**。
你的循环逻辑中大概率存在类似df.loc[i-1, col]的代码:当处理某一列的第一行(i=0)且该值为1时,会尝试访问标签为-1的行,但RangeIndex的标签只有0、1、2...,没有-1,因此触发KeyError。单列时可能刚好第一行是0,不需要访问前一行,所以没报错;多列时总有列的第一行是1,触发了这个问题。
2. 修复方案
有两种简单的修复思路:
- 边界判断+标签索引:在访问前一行前先检查i是否大于0,避免出现i-1=-1的情况,示例逻辑如下:
for col in df.columns: count = 0 for i in range(len(df)): if df.loc[i, col] == 1: # 第一行的1直接初始化为1,否则前一行是1则递增计数 if i == 0 or df.loc[i-1, col] != 1: count = 1 else: count += 1 df.loc[i, col] = count else: count = 0 - 改用位置索引
iloc:iloc支持通过位置偏移访问行,iloc[i-1]可正确获取前一行,但同样需要配合边界判断避免逻辑错误。
3. 更优实现方式
嵌套循环效率极低(尤其是大数据量场景),推荐用pandas矢量化操作,无需循环即可实现需求:
def process_col(col): # 生成分组键:当值从非1变为1时,分组ID递增 groups = (col != 1).cumsum() # 对每个分组内的1进行累计计数,0保持不变 return col.where(col == 0, col.groupby(groups).cumcount() + 1) # 对所有列应用处理函数 dfo = df.apply(process_col)
这个方法利用cumsum()生成连续1的分组,再通过groupby().cumcount()实现组内递增计数,完全矢量化,性能比循环提升几个数量级,同时天然支持多列处理。
内容的提问来源于stack exchange,提问作者iona negrea
相关产品推荐
相关产品推荐

