如何在pandas.query()中使用字典作为多条件进行过滤?
解决办法
报错原因
query()中直接使用@workers[person]会触发TypeError: unhashable type: 'Series',因为person是DataFrame的列(Series类型),而字典的键必须是可哈希的标量值,无法直接用Series作为键去索引字典。
方案一:用apply()逐行校验
逻辑直观,适合小数据量场景:
import pandas as pd import datetime as dt # 初始化数据 workers = { 'Alan': [dt.date(2017, 1, 15), dt.date(2020, 5, 4)], 'Ben': [dt.date(2018, 3, 28), dt.date(2021, 5, 7)] } df = pd.DataFrame({ 'event_id': ['1LFDVDX', '4DLDQVC', '5PEXVGH', '9OPCLXD'], 'person': ['Alan', 'Ben', 'Ben', 'John'], 'event_date': pd.to_datetime(['2018-10-28', '2022-02-01', '2019-09-05', '2020-06-15']).dt.date }) # 生成过滤掩码 mask = df.apply( lambda row: row['person'] in workers and workers[row['person']][0] <= row['event_date'] <= workers[row['person']][1], axis=1 ) result = df[mask] print(result)
输出结果:
event_id person event_date 0 1LFDVDX Alan 2018-10-28 2 5PEXVGH Ben 2019-09-05
方案二:字典转DataFrame合并过滤
性能更优,适合大数据量场景:
# 将workers字典转为区间DataFrame worker_ranges = pd.DataFrame.from_dict( workers, orient='index', columns=['start_date', 'end_date'] ).reset_index().rename(columns={'index': 'person'}) # 合并原数据与区间数据,仅保留匹配的员工 merged_df = df.merge(worker_ranges, on='person', how='inner') # 过滤日期在区间内的记录 result = merged_df[ (merged_df['event_date'] >= merged_df['start_date']) & (merged_df['event_date'] <= merged_df['end_date']) ][['event_id', 'person', 'event_date']] print(result)
方案三:改造query()写法
如果坚持使用query(),可以先通过映射生成区间列,再执行过滤:
# 为原数据添加员工对应的起止日期列 df['start_date'] = df['person'].map(lambda x: workers.get(x, [None, None])[0]) df['end_date'] = df['person'].map(lambda x: workers.get(x, [None, None])[1]) # 用query执行过滤 result = df.query( 'person in @workers and event_date >= start_date and event_date <= end_date' )[['event_id', 'person', 'event_date']] print(result)
内容的提问来源于stack exchange,提问作者exqplay
相关产品推荐
相关产品推荐

