如何在Python中匹配两个DataFrame的最相似行(基于金额与日期)
无匹配ID的DataFrame行匹配需求
需要在两个无匹配ID的DataFrame中,为每行找到最相似的对应行,通过比较Amount、Ocurred Date、Sale Date三列的相近值(最接近的金额与日期)实现匹配。
Df1数据
| ID | Amount | Ocurred Date | Sale Date |
|---|---|---|---|
| 1 | $100 | 02/20/2023 | 02/20/2022 |
| 2 | $20 | 01/20/2023 | 08/19/2022 |
Df2数据
| ID2 | Amount | Ocurred Date | Sale Date |
|---|---|---|---|
| 9 | $98 | 02/20/2023 | 02/21/2022 |
| 8 | $19 | 01/19/2023 | 08/23/2022 |
预期输出
| ID | ID2 |
|---|---|
| 1 | 9 |
| 2 | 8 |
实现方案(Python + Pandas)
1. 数据预处理
要计算相似度,首先得把数据转成可计算的格式:
- 金额列去掉
$符号,转成数值类型; - 日期列转成datetime类型,方便计算天数差。
代码如下:
import pandas as pd # 构造示例数据 df1 = pd.DataFrame({ 'ID': [1, 2], 'Amount': ['$100', '$20'], 'Ocurred Date': ['02/20/2023', '01/20/2023'], 'Sale Date': ['02/20/2022', '08/19/2022'] }) df2 = pd.DataFrame({ 'ID2': [9, 8], 'Amount': ['$98', '$19'], 'Ocurred Date': ['02/20/2023', '01/19/2023'], 'Sale Date': ['02/21/2022', '08/23/2022'] }) # 清洗金额列 df1['Amount'] = df1['Amount'].str.replace('$', '').astype(float) df2['Amount'] = df2['Amount'].str.replace('$', '').astype(float) # 转换日期格式 date_format = '%m/%d/%Y' df1['Ocurred Date'] = pd.to_datetime(df1['Ocurred Date'], format=date_format) df1['Sale Date'] = pd.to_datetime(df1['Sale Date'], format=date_format) df2['Ocurred Date'] = pd.to_datetime(df2['Ocurred Date'], format=date_format) df2['Sale Date'] = pd.to_datetime(df2['Sale Date'], format=date_format)
2. 匹配最相似行
我们通过计算金额差值绝对值、发生日期天数差绝对值、销售日期天数差绝对值的加权和来衡量相似度——加权和越小,两行越相似。为df1的每行找到df2中加权和最小的行即可:
def get_best_match(row, target_df): # 计算各项差异值 amount_diff = abs(row['Amount'] - target_df['Amount']) ocurred_day_diff = abs((row['Ocurred Date'] - target_df['Ocurred Date']).dt.days) sale_day_diff = abs((row['Sale Date'] - target_df['Sale Date']).dt.days) # 加权计算总差异(权重可根据业务优先级调整) total_diff = amount_diff * 0.5 + ocurred_day_diff * 0.3 + sale_day_diff * 0.2 # 返回差异最小的行的ID2 return target_df.loc[total_diff.idxmin(), 'ID2'] # 为df1每行匹配对应的ID2 df1['ID2'] = df1.apply(get_best_match, target_df=df2, axis=1) # 提取需要的结果列 match_result = df1[['ID', 'ID2']] print(match_result)
运行结果
ID ID2 0 1 9 1 2 8
补充说明
- 权重可以按需调整:比如如果金额匹配优先级最高,可以把金额的权重调至0.7,日期权重相应降低;
- 若数据量很大,逐行计算的效率偏低,可以用
sklearn.neighbors.NearestNeighbors这类KNN算法来优化匹配速度。
内容的提问来源于stack exchange,提问作者Clara Rodriguez
相关产品推荐
相关产品推荐

