如何基于A列+From/To列合并两个Pandas DataFrame?
Pandas 基于区间重叠的合并方案
要实现你需要的合并逻辑,核心是基于时间区间的重叠匹配,再结合相邻同属性区间的合并,最终得到目标结果。以下是具体实现步骤和代码:
步骤说明
- 日期格式标准化:把字符串类型的日期转成
datetime,避免字符串比较的误差。 - 生成子区间:收集两个表中所有的时间节点,排序后拆分出连续的子区间,确保覆盖所有可能的重叠范围。
- 匹配区间对应的属性值:对每个子区间,找到所有覆盖它的A表记录的
B值和B表记录的C值,生成组合记录。 - 合并相邻重复区间:将相邻且
B、C值完全相同的区间合并,简化结果。
完整代码
import pandas as pd def format_date(dt): """把datetime对象转成原示例的日期字符串格式(如'1-1-2024')""" return f"{dt.day}-{dt.month}-{dt.year}" # 加载原始数据 data_a = { 'From': ['1-1-2024', '2-2-2024'], 'To': ['1-1-9999', '1-1-9999'], 'A': ['XX', 'XX'], 'B': ['YY', 'ZZ'] } a = pd.DataFrame(data_a) data_b = { 'From': ['1-1-2024', '16-1-2024'], 'To': ['15-1-2024', '1-1-9999'], 'A': ['XX', 'XX'], 'C': ['LL', 'OO'] } b = pd.DataFrame(data_b) # 1. 转换日期列为datetime类型 a['From'] = pd.to_datetime(a['From'], dayfirst=True) a['To'] = pd.to_datetime(a['To'], dayfirst=True) b['From'] = pd.to_datetime(b['From'], dayfirst=True) b['To'] = pd.to_datetime(b['To'], dayfirst=True) # 2. 收集所有时间节点并生成子区间 all_dates = pd.concat([a['From'], a['To'], b['From'], b['To']]).unique() all_dates = sorted(all_dates) intervals = [(all_dates[i], all_dates[i+1]) for i in range(len(all_dates)-1)] # 3. 遍历子区间,匹配对应的B和C值 result = [] for s, e in intervals: # 筛选A表中与当前子区间有非零重叠的记录 a_matches = a[(a['From'] < e) & (a['To'] > s)]['B'].unique() # 筛选B表中与当前子区间有非零重叠的记录 b_matches = b[(b['From'] < e) & (b['To'] > s)]['C'].unique() # 跳过无匹配的区间 if len(a_matches) == 0 or len(b_matches) == 0: continue # 生成B和C的所有组合 for b_val in a_matches: for c_val in b_matches: result.append({ 'From': s, 'To': e, 'A': 'XX', 'B': b_val, 'C': c_val }) # 4. 合并相邻且B、C相同的区间 c_result = pd.DataFrame(result).sort_values(by=['From', 'B', 'C']).reset_index(drop=True) merged_intervals = [] if not c_result.empty: current = c_result.iloc[0].to_dict() for idx in range(1, len(c_result)): row = c_result.iloc[idx].to_dict() # 若当前区间的结束等于下一个区间的开始,且B、C相同,则合并 if current['To'] == row['From'] and current['B'] == row['B'] and current['C'] == row['C']: current['To'] = row['To'] else: merged_intervals.append(current) current = row merged_intervals.append(current) # 格式化日期并生成最终结果 c_final = pd.DataFrame(merged_intervals) c_final['From'] = c_final['From'].apply(format_date) c_final['To'] = c_final['To'].apply(format_date) print(c_final)
运行结果
From To A B C 0 1-1-2024 15-1-2024 XX YY LL 1 16-1-2024 1-1-9999 XX YY OO 2 2-2-2024 1-1-9999 XX ZZ OO
内容的提问来源于stack exchange,提问作者user23495865
相关产品推荐
相关产品推荐

