
本文介绍在 pandas 中实现非精确列匹配的 dataframe 合并方法:通过先按公共字段(如 deliveryperiod)左连接,再利用行级逻辑筛选 service 字段是否包含 vintage 值,最终补零并清理冗余列。
本文介绍在 pandas 中实现非精确列匹配的 dataframe 合并方法:通过先按公共字段(如 deliveryperiod)左连接,再利用行级逻辑筛选 service 字段是否包含 vintage 值,最终补零并清理冗余列。
在实际数据分析中,常遇到两表关键字段不完全一致但存在语义关联的情况——例如本例中 df1['Vintage'](如 "Vintage 2025")需匹配 df2['Service'](如 "ICE - Vintage 2025")中的子字符串,同时 DeliveryPeriod 必须严格相等。此时标准 pd.merge() 无法直接满足条件,需分步处理。
解决思路:先连接,后过滤,再修正
-
基础左连接(Left Join)
以DeliveryPeriod为键进行合并,保留df1全部记录,并引入df2的Service和FloatPrice列:
import pandas as pd df_merge = df1.merge(df2, on='DeliveryPeriod', how='left')
-
构建匹配掩码(Mask)
使用apply(axis=1)对每行判断:Vintage是否为字符串且是否被Service包含。注意需处理Vintage为None或NaN的情况(如df1第四行),避免TypeError:
mask = df_merge.apply(
lambda row:
pd.notna(row['Vintage']) and
isinstance(row['Vintage'], str) and
row['Vintage'] in row['Service'],
axis=1
)-
修正 FloatPrice:不匹配项设为 0.00
将未命中匹配的行FloatPrice置为0.00(符合示例输出要求),并删除临时列Service:
df_merge.loc[~mask, 'FloatPrice'] = 0.00 df_merge = df_merge.drop(columns=['Service'])
完整可运行代码
import pandas as pd
import numpy as np
# 构造示例数据
df1 = pd.DataFrame({
'BA': ['A', 'B', 'B', 'C'],
'Product': ['foo', 'foo', 'foo', 'bar'],
'FixedPrice': [10.00, 11.00, 12.00, 2.00],
'Vintage': ['Vintage 2025', 'Vintage 2025', 'Vintage 2024', None],
'DeliveryPeriod': ['Mar25', 'Dec25', 'Sep25', 'Nov25']
})
df2 = pd.DataFrame({
'Service': ['ICE - Vintage 2025', 'ICE - Vintage 2025',
'ICE - Vintage 2024', 'ICE - Vintage 2023'],
'DeliveryPeriod': ['Mar25', 'Dec25', 'Sep25', 'Nov25'],
'FloatPrice': [5.00, 4.00, 6.00, 1.00]
})
# 执行条件合并
df_merge = df1.merge(df2, on='DeliveryPeriod', how='left')
mask = df_merge.apply(
lambda row: pd.notna(row['Vintage']) and
isinstance(row['Vintage'], str) and
row['Vintage'] in row['Service'],
axis=1
)
df_merge.loc[~mask, 'FloatPrice'] = 0.00
df_merge = df_merge.drop(columns=['Service'])
print(df_merge)注意事项与优化建议
- ✅ 空值安全:显式检查
pd.notna()和isinstance(..., str)避免NaN in 'str'报错; - ⚠️ 性能提示:
apply(axis=1)是逐行操作,在大数据集上较慢;若需更高性能,可考虑预处理df2,提取Vintage子串并构造映射字典(如{'Mar25': {'Vintage 2025': 5.0}}),再用map()实现向量化查找; - ? 扩展性:若
Vintage格式不统一(如含空格、大小写差异),建议提前对Vintage和Service统一清洗(如.str.strip().str.upper()); - ? 结果验证:最后一行
Vintage=None→FloatPrice=0.00,符合业务逻辑中“无对应服务则浮动价为零”的约定。
该方法兼顾清晰性与实用性,是处理“模糊键匹配”类合并任务的经典范式。

















