咨询高效Pandas实现:统计各事件起止日期内的节假日数量
高效统计事件日期范围内的节假日数量
问题背景
现有两个DataFrame:
df1:存储事件名称及起止日期(Event列可能重复)df2:存储所有节假日日期
需要统计每个事件的起止日期(含两端)内包含的节假日数量,原逐行apply的方法在数据量大时效率极低。
示例数据
import pandas as pd from datetime import datetime df1 = pd.DataFrame({"Event": ["S1", "K1", "S2", "S3", "A1"], "Start": [datetime(2022,1,4), datetime(2022,1,15), datetime(2022,9,12), datetime(2022,11,11), datetime(2022,5,29)], "End": [datetime(2022,1,19), datetime(2022,1,29), datetime(2022,9,27), datetime(2022,11,22), datetime(2022,6,15)] }) df2 = pd.DataFrame({"Holidays": [datetime(2022,1,1), datetime(2022,1,6), datetime(2022,1,13), datetime(2022,6,10)]})
高效解决方案
方法一:广播+布尔索引分组计数
利用numpy广播机制实现向量化比较,避免逐行循环:
# 给df1添加临时索引用于后续分组 df1['temp_idx'] = df1.index # 广播判断每个节假日是否落在对应事件的日期区间内 mask = (df2['Holidays'].values[:, None] >= df1['Start'].values) & (df2['Holidays'].values[:, None] <= df1['End'].values) # 统计每个事件区间内的节假日数量,合并回原DataFrame holiday_counts = pd.DataFrame(mask.T, index=df1['temp_idx']).sum(axis=1).rename('holiday_count') df1 = df1.merge(holiday_counts, left_on='temp_idx', right_index=True).drop('temp_idx', axis=1)
方法二:IntervalIndex快速匹配计数
通过创建区间索引定位节假日所属事件,再统计数量:
# 创建包含所有事件区间的索引(闭区间) event_intervals = pd.IntervalIndex.from_arrays(df1['Start'], df1['End'], closed='both') # 查找每个节假日对应的事件区间索引,过滤无效匹配(-1表示不在任何区间) holiday_interval_idx = event_intervals.get_indexer(df2['Holidays']) valid_idx = holiday_interval_idx[holiday_interval_idx != -1] # 统计每个事件的节假日数量,无匹配的补0 holiday_counts = pd.Series(valid_idx).value_counts().reindex(df1.index, fill_value=0).rename('holiday_count') df1['holiday_count'] = holiday_counts
效果说明
两种方法均采用向量化操作,避免了apply的逐行处理,在大规模数据场景下效率远高于原方法,且不会出现内存占用过高的问题。
内容的提问来源于stack exchange,提问作者CharcoalG
相关产品推荐
相关产品推荐

