如何按条件合并Pandas DataFrame(支持通配符匹配)
带通配符的DataFrame条件合并(精确匹配优先)
我有两个DataFrame:
import pandas as pd df1 = pd.DataFrame([['A', 'B', 'C'], ['D', 'E', 'F'], ['A', 'B', 'D'], ['H', 'I', 'J']], columns=['Key1', 'Key2', 'Key3']) df2 = pd.DataFrame([['A', 'B', '*', 25], ['D', 'E', 'F', 50], ['*', '*', '*', 100]], columns=['Key11', 'Key21', 'Key31', 'Value'])
它们的结构如下:
- df1:
| Key1 | Key2 | Key3 |
|---|---|---|
| A | B | C |
| D | E | F |
| A | B | D |
| H | I | J |
- df2:
| Key11 | Key21 | Key31 | Value |
|---|---|---|---|
| A | B | * | 25 |
| D | E | F | 50 |
| * | * | * | 100 |
- 期望输出:
| Key1 | Key2 | Key3 | Value |
|---|---|---|---|
| A | B | C | 25 |
| D | E | F | 50 |
| A | B | D | 25 |
| H | I | J | 100 |
需求是按条件合并df1和df2:优先匹配精确键值,若未找到匹配项,则匹配包含通配符*的键规则(即每个键满足左表键 == 右表键或右表键 == '*')。我尝试过merge结合query的方式但未成功,示例代码如下:
query_line = "(Key1 == Key11 | Key11 == '*') & (Key2 == Key21 | Key21 == '*') & (Key3 == Key31| Key31 == '*')" out = df1.merge(df2, left_on=['Key1', 'Key2', 'Key3'], right_on=['Key11', 'Key21', 'Key31'], how='left').query(query_line)
请给出正确的实现方法。
解决方案
思路
核心逻辑是为每个df1的行计算与df2各规则的匹配优先级,精确匹配的键数量越多,优先级越高。最终为每个df1行选择优先级最高的规则对应的Value。
实现代码
import pandas as pd # 定义原始DataFrame df1 = pd.DataFrame([['A', 'B', 'C'], ['D', 'E', 'F'], ['A', 'B', 'D'], ['H', 'I', 'J']], columns=['Key1', 'Key2', 'Key3']) df2 = pd.DataFrame([['A', 'B', '*', 25], ['D', 'E', 'F', 50], ['*', '*', '*', 100]], columns=['Key11', 'Key21', 'Key31', 'Value']) # 生成笛卡尔积,获取所有可能的组合 merged = df1.assign(temp=1).merge(df2.assign(temp=1), on='temp').drop('temp', axis=1) # 计算匹配得分:统计精确匹配的键数量 merged['match_score'] = ( (merged['Key1'] == merged['Key11']) + (merged['Key2'] == merged['Key21']) + (merged['Key3'] == merged['Key31']) ) # 过滤不符合通配符规则的组合 valid_mask = ( (merged['Key11'] == '*') | (merged['Key1'] == merged['Key11']) ) & ( (merged['Key21'] == '*') | (merged['Key2'] == merged['Key21']) ) & ( (merged['Key31'] == '*') | (merged['Key3'] == merged['Key31']) ) merged = merged[valid_mask] # 按df1行分组,选择得分最高的匹配项 result = merged.sort_values('match_score', ascending=False).groupby(['Key1', 'Key2', 'Key3']).first().reset_index() # 保留目标列 result = result[['Key1', 'Key2', 'Key3', 'Value']] print(result)
代码说明
- 笛卡尔积合并:通过临时列实现全连接,确保不遗漏任何潜在的匹配规则组合。
- 匹配得分计算:用精确匹配的键数量作为优先级依据,得分越高匹配度越高。
- 无效组合过滤:剔除那些右表键既不是
*也不等于左表键的无效组合。 - 最优匹配选择:按df1的行分组,排序后取得分最高的项,保证每个df1行只保留优先级最高的Value。
运行后输出结果与期望完全一致。
内容的提问来源于stack exchange,提问作者LUIS BLEDA TORRES
相关产品推荐
相关产品推荐

