
本文介绍在 pandas 中实现非精确列对齐的 dataframe 合并:当需根据一个字段是否“包含”另一字段的字符串内容(如 vintage 值是否出现在 service 字符串中),同时满足另一字段(如 deliveryperiod)完全匹配时,如何高效完成条件关联并填充默认值。
本文介绍在 pandas 中实现非精确列对齐的 dataframe 合并:当需根据一个字段是否“包含”另一字段的字符串内容(如 vintage 值是否出现在 service 字符串中),同时满足另一字段(如 deliveryperiod)完全匹配时,如何高效完成条件关联并填充默认值。
在实际数据分析中,常遇到两表字段语义相关但结构不一致的情况——例如 df1['Vintage'] 为 "Vintage 2025",而 df2['Service'] 为 "ICE - Vintage 2025"。此时无法直接使用 pd.merge() 的等值连接,需结合字符串匹配与多条件逻辑完成“语义级关联”。
推荐做法是先按确定性字段(如 DeliveryPeriod)左连接,再通过布尔掩码校验语义一致性,并修正结果。以下是完整、可复现的解决方案:
import pandas as pd
# 构造示例数据
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]
})
# Step 1: 基于 DeliveryPeriod 左连接(保留 df1 全部行)
merged = df1.merge(df2, on='DeliveryPeriod', how='left')
# Step 2: 构建匹配掩码 —— Vintage 非空且是 Service 的子字符串
# 注意:'None' 字符串需排除;NaN 值用 pd.isna() 判断更健壮
mask = (
~pd.isna(merged['Vintage']) &
(merged['Vintage'] != 'None') &
merged.apply(lambda row: row['Vintage'] in str(row['Service']), axis=1)
)
# Step 3: 不匹配行的 FloatPrice 置为 0.00,删除冗余列
merged.loc[~mask, 'FloatPrice'] = 0.00
merged = merged.drop(columns=['Service'])
# 输出结果
print(merged)
✅ 输出结果与预期一致:
BA Product FixedPrice Vintage DeliveryPeriod FloatPrice 0 A foo 10.0 Vintage 2025 Mar25 5.0 1 B foo 11.0 Vintage 2025 Dec25 4.0 2 B foo 12.0 Vintage 2024 Sep25 6.0 3 C bar 2.0 None Nov25 0.0
⚠️ 关键注意事项:
-
apply(axis=1)在大数据集上性能较低,若性能敏感,可预处理df2:提取Vintage子串并构造映射字典,再用map()实现向量化查找; -
Vintage == 'None'是业务占位符,非缺失值,务必显式排除,避免误匹配; - 使用
str(row['Service'])防止Service列含 NaN 导致in操作报错; - 最终
FloatPrice类型保持float64,便于后续数值计算。
该方法平衡了可读性、健壮性与通用性,适用于任意“字段A值是否为字段B字符串子串 + 其他字段等值”的混合关联场景。










