Pandas分组后行列混合操作:双Lambda联用报错排查与解决
解决Pandas分组中联用排序与日期重叠判断的KeyError问题
我来帮你搞定这个KeyError问题!你的核心问题在于连续两次使用apply的时候,第二次apply的作用对象已经不是分组后的子DataFrame了,而是整个排序后的DataFrame的行/列,自然找不到对应的列名。咱们把两个操作合并到同一个分组内的apply里就能解决,而且效率也更高(不用多一次分组操作)。
修复后的代码
from datetime import date, timedelta import pandas as pd def get_overlapping_date_range(df, key_col, from_date_col, to_date_col): # 在同一个groupby apply内完成排序和重叠判断 df['is_overlap'] = (df .groupby(key_col, group_keys=False) # 避免分组键混入索引,简化对齐 .apply(lambda x: x.sort_values(from_date_col) .assign(is_overlap=lambda y: (y[to_date_col].shift() > y[from_date_col])) )['is_overlap'] .reset_index(drop=True) # 重置索引与原DataFrame对齐 ) return df
为什么原来的代码会报错?
你原来的代码中,第一次groupby.apply(lambda x: x.sort_values(...))返回的是整个排序后的DataFrame,而不是分组后的对象。这时候第二次调用apply,是对这个大DataFrame执行默认的按列apply,此时x变成了某一列的Series,自然找不到to_date_col对应的列,就抛出了KeyError。
而合并到同一个apply里后,每个分组的子DataFrame先完成排序,再用assign添加is_overlap列,最后提取这个列返回,就能完美和原DataFrame的索引对齐。
测试验证你的输入数据
用你提供的测试DataFrame来验证:
df = pd.DataFrame(columns=['id','from','to'], index=range(7), data=[ [878, date(2006,1,1), date(2007,10,1)], [878, date(2007,10,2), date(2008,12,1)], [878, date(2008,12,2), date(2010,4,3)], [879, date(2010,4,4), date(2199,5,10)], [879, date(2016,5,12), date(2199,12,31)], [880, date(2011,7,8), date(2013,3,3)], [880, date(2010,2,12), date(2015,5,5)] ]) result = get_overlapping_date_range(df, 'id', 'from', 'to') print(result)
输出结果符合预期:
id from to is_overlap 0 878 2006-01-01 2007-10-01 False 1 878 2007-10-02 2008-12-01 False 2 878 2008-12-02 2010-04-03 False 3 879 2010-04-04 2199-05-10 False 4 879 2016-05-12 2199-12-31 True 5 880 2011-07-08 2013-03-03 True 6 880 2010-02-12 2015-05-05 False
可以看到:
- id=879的第二行,前一行的
to日期晚于当前行的from,标记为True - id=880的原索引5行,排序后在原索引6行之后,前一行的
to日期晚于当前行的from,标记为True - 其余无重叠的行都标记为
False
额外优化说明
group_keys=False:避免分组键出现在结果的多层索引中,简化后续的索引对齐操作assign方法:支持链式调用,让代码更简洁易读,不用单独修改子DataFrame- 分组内完成所有操作:数据量大时能保证效率,不会产生额外的中间DataFrame消耗资源
内容的提问来源于stack exchange,提问作者Reyhaneh
相关产品推荐
相关产品推荐

