合并存在重叠项的两个DataFrame并保留原始顺序
问题描述
现有两个包含区域名称的DataFrame,其中area1_name和area2_name存在重叠项,需要将两个区域名称合并为一个长列表,并按指定顺序排列。
原始数据:
import pandas as pd df1 = pd.DataFrame({'area1_index': [0,1,2,3,4,5], 'area1_name': ['AL','AK','AZ','AR','CA','CO']}) df2 = pd.DataFrame({'area2_index': [0,1,2,3,4,5,6], 'area2_name': ['MN','AL','CT','TX','AK','AR','CA']})
期望得到的最终结果:
final = pd.DataFrame({'area1_index': [pd.NA,0,pd.NA,pd.NA,1,2,3,4,5], 'area1_name': [pd.NA,'AL',pd.NA,pd.NA,'AK','AZ','AR','CA','CO'], 'area2_index': [0,1,2,3,4,pd.NA,5,6,pd.NA], 'area2_name':['MN','AL','CT','TX','AK',pd.NA,'AR','CA',pd.NA]})
尝试手动识别重叠区域和缺失部分再合并,但合并后会自动按索引排序,无法得到期望的顺序:
df1_df2_overlap = pd.DataFrame({'area1_index': [0,1,3,4], 'area2_index': [1,4,5,6], 'area1_name': ['AL','AK','AR','CA']}) df2_missing = pd.DataFrame({'area2_index': [0,2,3], 'area2_name': ['MN','CT','TX']}) df3 = pd.merge(df1, df2, "outer") df4 = pd.merge(df3, df2_missing, "outer")
解决方案
方法一:合并后按自定义映射排序(无需手动拆分)
不需要提前识别重叠/缺失部分,先通过外连接合并数据,再为每个区域名称指定排序优先级即可:
- 外连接合并两个DataFrame,以区域名称为连接键:
merged = pd.merge(df1, df2, left_on='area1_name', right_on='area2_name', how='outer')
- 定义目标排序顺序,生成排序映射字典:
# 排序规则:df2独有项 → 重叠项(按df1顺序) → df1独有项 order = ['MN', 'AL', 'CT', 'TX', 'AK', 'AZ', 'AR', 'CA', 'CO'] sort_mapping = {name: idx for idx, name in enumerate(order)}
- 添加临时排序列,按该列排序后整理格式:
# 统一提取区域名称用于排序 merged['sort_key'] = merged['area1_name'].fillna(merged['area2_name']).map(sort_mapping) # 排序并重置索引 result = merged.sort_values('sort_key').reset_index(drop=True) # 调整列顺序为期望格式 result = result[['area1_index', 'area1_name', 'area2_index', 'area2_name']]
方法二:分块拼接(贴合原始逻辑)
如果想保留拆分重叠/缺失的思路,可按目标顺序拼接各部分:
- 提取各部分数据:
# df2独有的区域 df2_unique = df2[~df2['area2_name'].isin(df1['area1_name'])] # 重叠区域(按df1的顺序排序) overlap = pd.merge(df1, df2, left_on='area1_name', right_on='area2_name') overlap = overlap.set_index('area1_name').loc[df1['area1_name'][df1['area1_name'].isin(df2['area2_name'])]].reset_index() # df1独有的区域 df1_unique = df1[~df1['area1_name'].isin(df2['area2_name'])]
- 按顺序拼接并整理格式:
# 统一临时列名方便拼接 df2_unique = df2_unique.rename(columns={'area2_name': 'name'}) overlap = overlap.rename(columns={'area1_name': 'name'}) df1_unique = df1_unique.rename(columns={'area1_name': 'name'}) # 按目标顺序拼接 combined = pd.concat([df2_unique, overlap, df1_unique], ignore_index=True) # 恢复原始列名并填充缺失值 result = combined.assign( area1_name=combined['name'].where(combined['area1_index'].notna(), pd.NA), area2_name=combined['name'].where(combined['area2_index'].notna(), pd.NA) ).drop('name', axis=1)[['area1_index', 'area1_name', 'area2_index', 'area2_name']]
内容的提问来源于stack exchange,提问作者Jen
相关产品推荐
相关产品推荐

