如何判断Pandas主DataFrame的日期是否落在另一DataFrame的日期范围内
多日期范围匹配解决方案
需求说明
现有两个Pandas DataFrame:
main_df:约20万条事件数据,包含事件编号、时间戳及其他字段df_ranges:包含多个不重叠的日期范围,每个范围对应唯一名称
需要为main_df新增一列in_range,标记每条记录的时间属于哪个范围,不属于任何范围则为None。
数据示例
main_df
| event_nr | date | detail_1 | detail_2 |
|---|---|---|---|
| e_0001 | 2010-01-02 07:30:00 | 1 | 100 |
| e_0002 | 2010-06-05 07:30:00 | 0 | 132 |
df_ranges
| start | end | name |
|---|---|---|
| 2010-02-25 | 2010-03-06 | range_1 |
| 2010-06-02 | 2010-06-08 | range_2 |
期望结果
| event_nr | date | detail_1 | detail_2 | in_range |
|---|---|---|---|---|
| e_0001 | 2010-01-02 07:30:00 | 1 | 100 | None |
| e_0002 | 2010-06-05 07:30:00 | 0 | 132 | range_2 |
高效实现方案(适合20万条数据)
由于数据量较大,推荐使用pd.merge_asof,这是专门针对有序键的高效合并方法,适合处理范围匹配场景:
步骤1:统一日期类型
先确保所有日期列都是datetime类型:
import pandas as pd # 转换main_df的date列 main_df['date'] = pd.to_datetime(main_df['date']) # 转换df_ranges的start和end列 df_ranges['start'] = pd.to_datetime(df_ranges['start']) df_ranges['end'] = pd.to_datetime(df_ranges['end'])
步骤2:排序范围数据
merge_asof要求右侧DataFrame按合并键排序,这里按start排序:
df_ranges_sorted = df_ranges.sort_values('start')
步骤3:执行范围匹配
使用merge_asof匹配,同时过滤掉超出end范围的记录:
# 先按date和start做向后合并 merged = pd.merge_asof( main_df.sort_values('date'), df_ranges_sorted, left_on='date', right_on='start', direction='backward' ) # 过滤掉date大于end的记录,将对应的name设为None merged['in_range'] = merged.apply( lambda x: x['name'] if x['date'] <= x['end'] else None, axis=1 ) # 保留原main_df的列顺序,去掉合并时新增的start/end列 result = merged[['event_nr', 'date', 'detail_1', 'detail_2', 'in_range']]
备选方案(小数据量适用)
如果数据量较小,可以用apply遍历每条记录,但效率较低,不适合20万条数据:
def get_range_name(date): for _, row in df_ranges.iterrows(): if row['start'] <= date <= row['end']: return row['name'] return None main_df['in_range'] = main_df['date'].apply(get_range_name)
内容的提问来源于stack exchange,提问作者Con-cat-enate
相关产品推荐
相关产品推荐

