Pandas使用df.loc筛选数据时出现KeyError的原因及修正
Pandas筛选包含指定所有元素的列表行:错误原因与修正
错误原因
原代码里的all(n in df['Num'] for n in numbers)逻辑完全偏离需求:
df['Num']是Pandas的Series对象,n in df['Num']判断的是n是否在Series的索引里,而非每一行的列表元素中。all()会把整个生成器转换成单一布尔值(True/False),而df.loc[]收到单一布尔值时,会把它当作索引标签去查找,自然找不到名为True或False的索引,因此触发KeyError。
而正确代码用df['Num'].apply(...)的核心原因:
apply会遍历Num列的每一个列表元素,对每个列表单独执行all(n in c for n in numbers),检查该列表是否包含numbers的所有元素。- 最终返回的是布尔Series,每个元素对应一行的筛选结果,
df.loc[]可以正确识别这种布尔索引,实现行筛选。
修正方案
把筛选逻辑改成逐行检查每个列表的形式,以下两种写法都可以:
方案1:保持apply写法(清晰直观)
import pandas as pd data = {'Num': [[1,2,100], [10,20,30], [1,2,30],[1,2,200],[4,0,9]],'Id':range(5)} df = pd.DataFrame(data) numbers = [1,2] # 对每行的Num列表,检查是否包含所有指定元素 filtered_df = df.loc[df['Num'].apply(lambda c: all(n in c for n in numbers))] print(filtered_df)
方案2:集合子集优化(适合元素较多的场景)
把numbers转成集合,用子集判断提升性能:
import pandas as pd data = {'Num': [[1,2,100], [10,20,30], [1,2,30],[1,2,200],[4,0,9]],'Id':range(5)} df = pd.DataFrame(data) num_set = set([1,2]) # 检查指定集合是否是当前列表的子集 filtered_df = df.loc[df['Num'].apply(lambda c: num_set.issubset(c))] print(filtered_df)
两种方案运行后都会得到正确结果:
Num Id 0 [1, 2, 100] 0 2 [1, 2, 30] 2 3 [1, 2, 200] 3
内容的提问来源于stack exchange,提问作者Franck
相关产品推荐
相关产品推荐

