如何用Pandas基于多列匹配替换project_id且保持数据集结构不变?
解决方案
问题根源
- 列名不匹配:数据集A的列是
deliv,但代码中使用了delivery,导致匹配逻辑失效。 - 多对多匹配:B中存在同一组匹配键(
Tags,ID,qtr,TYPE,msc)对应多个Project Name的情况(如2022/BR/Q2 2022/dd/d对应两个项目名),左连接时生成笛卡尔积,导致行数激增。
正确实现代码(完全匹配期望结果)
从期望结果可看出,A中同一匹配键的不同行对应B中NUM列的不同值(如A中dd1对应B的01,dd2对应02),因此需补充NUM作为匹配条件:
import pandas as pd # 1. 从A的project_id中提取NUM并补零为两位(匹配B的NUM格式) df_A['NUM'] = df_A['project_id'].str.extract(r'(\d+)').str.zfill(2) # 2. 准备B的映射表,保留需要的匹配列 df_B_mapping = df_B[['Project Name', 'Tags', 'ID', 'qtr', 'TYPE', 'msc', 'NUM']] # 3. 执行左连接,使用完整匹配键(含NUM),避免多对多膨胀 df_merged = pd.merge( df_A, df_B_mapping, how='left', left_on=['Year', 'ID', 'deliv', 'type', 'vendor', 'NUM'], right_on=['Tags', 'ID', 'qtr', 'TYPE', 'msc', 'NUM'] ) # 4. 替换project_id:有匹配则用B的Project Name,无匹配则保留原A的值 df_A['project_id'] = df_merged['Project Name'].combine_first(df_A['project_id']) # 5. 移除临时添加的NUM列,恢复原A的列结构 df_A.drop('NUM', axis=1, inplace=True) # 输出结果 print(df_A)
简化方案(若无需区分NUM)
若允许同一匹配键仅取B中第一个出现的Project Name,可先对B去重再连接:
# 对B按匹配键去重,保留第一个项目名 df_B_unique = df_B.drop_duplicates(subset=['Tags', 'ID', 'qtr', 'TYPE', 'msc'], keep='first') # 执行左连接,修正列名错误 df_merged = pd.merge( df_A, df_B_unique[['Project Name', 'Tags', 'ID', 'qtr', 'TYPE', 'msc']], how='left', left_on=['Year', 'ID', 'deliv', 'type', 'vendor'], right_on=['Tags', 'ID', 'qtr', 'TYPE', 'msc'] ) # 替换project_id df_A['project_id'] = df_merged['Project Name'].combine_first(df_A['project_id'])
内容的提问来源于stack exchange,提问作者Lynn
相关产品推荐
相关产品推荐

