如何基于NUM列最近值合并两个DataFrame并保留对应多行结果?
问题描述
现有两个DataFrame:
import pandas as pd DF1 = pd.DataFrame({ 'NUM1': [100, 100, 200], 'Car': ['Honda', 'Honda', 'Volvo'], 'COLOR': ['blue', 'yellow', 'red'] }) DF2 = pd.DataFrame({ 'NUM2': [110, 110, 230, 230], 'Car': ['Honda', 'Honda', 'Volvo', 'Volvo'], 'STATE': ['good', 'bad', 'not bad', 'excellent'] })
想要基于NUM1和NUM2的最近值合并,得到如下目标结果:
NUM CAR COLOR STATE 0 100 HONDA blue good 1 100 HONDA blue bad 2 100 HONDA yellow good 3 100 HONDA yellow bad 4 200 VOLVO red not bad 5 200 VOLVO red excellent
试了pd.merge_asof:
df3 = pd.merge_asof(df1, df2, left_on="NUM1", right_on="NUM2")
但结果只返回每个匹配组的第一行,达不到要求,该怎么处理?
解决方案
pd.merge_asof默认只会给左表的每一行匹配右表中最近的单行,所以拿不到同一匹配组下的所有STATE值。要实现需求,得先建立NUM1和对应最近NUM2的映射关系,再基于Car和这个映射做全量合并:
步骤1:提取每个车型对应的唯一NUM2值
看你的数据,同一车型下的NUM2是相同的,先把每个车型对应的NUM2提出来:
# 按Car分组,取每个车型对应的NUM2(因为同一车型NUM2一致,取first就行) num_mapping = DF2.groupby('Car')['NUM2'].first().reset_index()
步骤2:给DF1匹配对应的NUM2
直接按车型把NUM2关联到DF1上:
df1_with_num2 = pd.merge(DF1, num_mapping, on='Car', how='left')
步骤3:合并两个表生成全量组合
现在基于车型和NUM2合并DF1和DF2,就能自动生成所有COLOR和STATE的组合:
df3 = pd.merge(df1_with_num2, DF2, on=['Car', 'NUM2'], how='left') # 整理列名和格式,和目标结果对齐 df3 = df3.rename(columns={'NUM1': 'NUM', 'Car': 'CAR'}) df3['CAR'] = df3['CAR'].str.upper() df3 = df3[['NUM', 'CAR', 'COLOR', 'STATE']].reset_index(drop=True)
运行后得到的结果就是你要的目标DataFrame。
如果同一车型有多个不同NUM2的情况
要是DF2里同一车型有多个不同的NUM2值,就得先给DF1的每个NUM1找到对应车型下最近的NUM2,再合并:
# 先按车型和NUM排序,merge_asof要求输入是有序的 DF1_sorted = DF1.sort_values(['Car', 'NUM1']) DF2_sorted = DF2.sort_values(['Car', 'NUM2']) # 按车型分组,给每个NUM1匹配最近的NUM2 df1_with_num2 = pd.merge_asof( DF1_sorted, DF2_sorted[['Car', 'NUM2']].drop_duplicates(), # 先去重每个车型的NUM2 left_on='NUM1', right_on='NUM2', by='Car', direction='nearest' # 找最近值,比默认的向后找更准确 ) # 再合并DF2得到所有STATE组合 df3 = pd.merge(df1_with_num2, DF2, on=['Car', 'NUM2'], how='left') # 后续列名整理同上
内容的提问来源于stack exchange,提问作者Hamouza
相关产品推荐
相关产品推荐

