使用bisect操作Pandas DataFrame遭遇KeyError问题求助
bisect模块是给Python原生序列(比如list、tuple)设计的,它内部通过整数位置访问元素,但你传入的是pandas的Series对象——Series的索引是标签,不是连续的位置序号。当bisect计算出要访问的位置(比如你案例里的57),它会用series[57]去取元素,但这个切片后的Series的标签里根本没有57,自然就抛出KeyError了。
比如你补充测试里的X[1:10]['x'],这个Series的标签是1到9,bisect要找位置0的元素时,会尝试取series[0],但标签0不存在,所以报错KeyError:0,和你看到的情况完全对应。
方法1:转成list再用bisect
把Series转换成原生list,这样bisect就会按位置访问,不会碰标签索引:
import bisect # 先把切片后的Series转成list slice_list = X['x'].iloc[116:231].tolist() # 找在切片list中的位置 pos_in_slice = bisect.bisect_left(slice_list, 0.15) # 转换成原DataFrame中的索引 original_pos = 116 + pos_in_slice
因为你的切片起始是116,所以加上这个偏移量就是原数据里的索引,和你预期的116一致(slice_list里第一个元素就是0.275,bisect_left返回0,0+116=116)。
方法2:用pandas自带的searchsorted(更高效)
pandas的Series自带searchsorted方法,专门针对已排序的序列做二分查找,比转list再用bisect更高效,而且直接处理标签/位置:
# 直接在整个已排序的Series中找第一个大于等于0.15的位置 # side='left'表示找第一个>=x的位置,正好符合你要的第一个大于0.15的需求(因为你的数据里没有等于0.15的) pos = X['x'].searchsorted(0.15, side='left')
如果只想在116到231的范围内查找,也可以切片后再用:
slice_series = X['x'].iloc[116:231] pos_in_slice = slice_series.searchsorted(0.15, side='left') original_pos = 116 + pos_in_slice
你要找的是“第一个大于指定值的索引”,当数据里没有等于指定值的元素时,bisect_left和searchsorted(side='left')返回的就是第一个大于该值的位置,完全符合需求。如果数据里可能有等于的情况,要区分“大于”和“大于等于”,可以调整side参数或者后续判断。
内容的提问来源于stack exchange,提问作者Kubra

