如何实现两个Pandas DataFrame的精确列+近似列行匹配标记?
问题描述
现有两个Pandas DataFrame(df1、df2),共享city和date两列。需要给df1新增paired列,标记满足以下条件的记录:
city列与df2中某条记录精确匹配date列与df2中对应城市的记录日期相差≤1天
不满足条件的记录标记为False。两列均非唯一键,值在两表中均可重复。
示例输入
df1
| city | date |
|---|---|
| New York | 1/1/2024 |
| New York | 1/5/2024 |
| Chicago | 1/2/2024 |
| Chicago | 1/5/2024 |
| Houston | 1/3/2024 |
df2
| city | date |
|---|---|
| New York | 1/2/2024 |
| Chicago | 1/5/2024 |
期望输出
| city | date | paired |
|---|---|---|
| New York | 1/1/2024 | True |
| New York | 1/5/2024 | False |
| Chicago | 1/2/2024 | False |
| Chicago | 1/5/2024 | True |
| Houston | 1/3/2024 | False |
高效实现方案:使用
merge_asof Pandas的merge_asof是专门针对有序键近似匹配优化的函数,性能远优于循环、apply或笛卡尔积合并,尤其适合处理大规模数据。
步骤1:转换日期为datetime类型
首先必须将date列转为datetime格式,才能进行日期差值计算:
import pandas as pd # 转换日期列格式 df1['date'] = pd.to_datetime(df1['date']) df2['date'] = pd.to_datetime(df2['date'])
步骤2:执行近似匹配
先对两个DataFrame按city和date排序(merge_asof要求右表按匹配列排序),再指定精确匹配和范围匹配规则:
# 按city和date排序 df1_sorted = df1.sort_values(['city', 'date']) df2_sorted = df2.sort_values(['city', 'date']) # 执行近似匹配:同城市内,日期差值≤1天即视为匹配 merged = pd.merge_asof( df1_sorted, df2_sorted, by='city', # 精确匹配的分组列 on='date', # 近似匹配的列 tolerance=pd.Timedelta(days=1), # 日期允许的最大差值 direction='nearest' # 匹配最近的符合条件记录 ) # 标记paired列:匹配成功则df2的date列不为空 df1['paired'] = merged['date_y'].notna()
参数说明
by='city':确保仅在同一城市范围内查找日期匹配项tolerance=pd.Timedelta(days=1):设置日期允许的差值范围为±1天direction='nearest':只要同城市内存在日期在±1天内的记录,即判定为匹配;若需限定仅向前/向后匹配,可改为forward或backward
备选方案(小数据量适用)
如果数据量较小,也可以用groupby结合apply实现,但性能远不如merge_asof,不推荐用于大规模数据:
# 按城市分组存储df2的日期集合 city_dates = df2.groupby('city')['date'].apply(set) def check_match(row): if row['city'] not in city_dates: return False # 检查是否存在日期差值≤1天的记录 for dt in city_dates[row['city']]: if abs(row['date'] - dt) <= pd.Timedelta(days=1): return True return False df1['paired'] = df1.apply(check_match, axis=1)
性能对比
merge_asof:时间复杂度接近O(n log n)(主要来自排序),适合百万级以上数据apply+循环:时间复杂度O(n*m)(n为df1行数,m为df2同城市平均行数),数据量大时性能极差
内容的提问来源于stack exchange,提问作者NaiveBayesian
相关产品推荐
相关产品推荐

