如何基于重叠日期在Python中合并两个DataFrame
基于日期区间交集合并DataFrame的解决方案
核心思路
按Key分组,提取每个Key下所有涉及的日期节点(包括两个DataFrame的起始、结束日期),将这些节点排序后生成连续的时间分段区间,再逐个区间匹配对应的char1和char2,最终得到分段后的匹配结果。
具体实现步骤
1. 日期格式转换
先把两个DataFrame里的日期字符串统一转成datetime类型,避免字符串比较的误差:
import pandas as pd # 定义日期解析格式 date_format = "%d/%m/%Y" # 处理df1的日期列 df1['in_date'] = pd.to_datetime(df1['in_date'], format=date_format) df1['out_date'] = pd.to_datetime(df1['out_date'], format=date_format) # 处理df2的日期列 df2['st_date'] = pd.to_datetime(df2['st_date'], format=date_format) df2['end_date'] = pd.to_datetime(df2['end_date'], format=date_format)
2. 生成每个Key的时间分割点
对每个Key,收集df1的in_date、out_date和df2的st_date、end_date,去重后排序,得到用于分割时间的节点列表:
# 合并两个df的日期数据,按Key分组收集所有日期 all_dates = pd.concat([ df1[['Key', 'in_date']].rename(columns={'in_date': 'date'}), df1[['Key', 'out_date']].rename(columns={'out_date': 'date'}), df2[['Key', 'st_date']].rename(columns={'st_date': 'date'}), df2[['Key', 'end_date']].rename(columns={'end_date': 'date'}) ]) # 按Key分组,对日期去重并排序 split_dates = all_dates.groupby('Key')['date'].apply(lambda x: sorted(x.unique())).reset_index()
3. 生成连续时间区间
基于分割点,为每个Key生成连续的start和end区间:
# 生成区间函数 def create_intervals(dates): intervals = [] for i in range(len(dates)-1): intervals.append({'start': dates[i], 'end': dates[i+1]}) return pd.DataFrame(intervals) # 对每个Key生成区间 interval_df = split_dates.explode('date', ignore_index=False) interval_df = interval_df.groupby('Key').apply(lambda x: create_intervals(x['date'])).reset_index() interval_df = interval_df.drop(columns='level_1').rename(columns={'Key': 'key'})
4. 匹配每个区间对应的char1和char2
编写函数,对每个区间,找到df1中完全包含该区间的char1(如果没有则为NaN),同理匹配df2的char2:
def get_char1(row, df1): # 筛选当前key下,in_date <= start 且 out_date >= end的记录 mask = (df1['Key'] == row['key']) & (df1['in_date'] <= row['start']) & (df1['out_date'] >= row['end']) res = df1.loc[mask, 'char1'].unique() return res[0] if len(res) > 0 else pd.NA def get_char2(row, df2): mask = (df2['Key'] == row['key']) & (df2['st_date'] <= row['start']) & (df2['end_date'] >= row['end']) res = df2.loc[mask, 'char2'].unique() return res[0] if len(res) > 0 else pd.NA # 应用函数匹配特征 interval_df['char1'] = interval_df.apply(get_char1, args=(df1,), axis=1) interval_df['char2'] = interval_df.apply(get_char2, args=(df2,), axis=1)
5. 格式化日期输出(可选)
如果需要把datetime类型转回原字符串格式:
interval_df['start'] = interval_df['start'].dt.strftime(date_format) interval_df['end'] = interval_df['end'].dt.strftime(date_format)
最终结果
运行完上述代码后,interval_df的结构和内容就会和你期望的结果一致。
内容的提问来源于stack exchange,提问作者Dept
相关产品推荐
相关产品推荐

