代码之家  ›  专栏  ›  技术社区  ›  Lynn

转换和替换现有列中的值如果使用panda存在多个匹配值

  •  -2
  • Lynn  · 技术社区  · 2 年前

    我有两个数据集:A和B。

    如果数据集A year , ID , delivery , type 和 vendor 列都与数据集B的匹配 Tags , 身份证件 , qtr , TYPE 和 msc 列,然后我想替换 project_id 的数据集A中匹配行的 Project Name 从数据集B中相应的行中删除。否则,我不想更改 项目_id 在一个。

    数据集A:

    Year    ID  deliv   Gen type    vendor  project_id
    2022    BR  Q2 2022 L   aa      d       BR2 aa1 Q2 2022 - L
    2022    BR  Q2 2022 L   dd      d       BR2 dd1 Q2 2022 - L
    2022    BR  Q2 2022 L   dd      d       BR2 dd2 Q2 2022 - L
    2022    BR  Q3 2022 L   bb      d       BR2 bb1 Q3 2022 - L
    2022    BR  Q4 2022 L   aa      d       BR2 aa1 Q4 2022 - L
    2022    BR  Q4 2022 L   dd      nd      BR2 dd1 Q4 2022 - L
    

    数据集B:

    Project Name          Tags  ID      qtr     TYPE    msc NUM
    BB H_AA01 Q4 2022     2022  BOLOL   Q4 2022 aa      d   01
    BR2 H_DD_nd02 Q4 2022 2022  BR      Q4 2022 dd      nd  02
    BR2 BB01 Q3.2022      2022  BR      Q3 2022 bb      d   01
    BR2 H_DD01 Q2 2022    2022  BR      Q2 2022 dd      d   01
    BR2 H_DD02 Q2 2022    2022  BR      Q2 2022 dd      d   02
    BR2 H_AA01 Q2 2022    2022  BR      Q2 2022 aa      d   01
        
    

    所需结果:

    Year    ID  delivery    Gen type    vendor  project_id
    2022    BR  Q2 2022     L   aa      d       BR2 H_AA01 Q2 2022
    2022    BR  Q2 2022     L   dd      d       BR2 H_DD01 Q2 2022
    2022    BR  Q2 2022     L   dd      d       BR2 H_DD02 Q2 2022
    2022    BR  Q3 2022     L   bb      d       BR2 BB01 Q3.2022
    2022    BR  Q4 2022     L   aa      d       BR2 aa1 Q4 2022 - L
    2022    BR  Q4 2022     L   dd      nd      BR2 H_DD_nd02 Q4 2022
    

    这是我目前的尝试:

    df_merged = pd.merge(df_A, df_B[['Project Name', 'Tags', 'ID', 'qtr', 'TYPE', 'msc']], 
                         how='left', 
                         left_on=['Year', 'ID', 'delivery', 'type', 'vendor'], 
                         right_on=['Tags', 'ID', 'qtr', 'TYPE', 'msc'])
    
    # Replacing 'project_id' in A with 'Project Name' from B where there is a match
    df_merged['project_id'] = df_merged['Project Name'].combine_first(df_merged['project_id'])
    
    # Dropping unnecessary columns from the merge
    df_final = df_merged.drop(['Project Name', 'Tags', 'qtr', 'TYPE', 'msc'], axis=1)
    

    然而,上面的脚本破坏了我的数据集,创建了不必要的行和多列。

    最终输出的行和列的数量应与原始数据集的相同。唯一的区别是 项目_id 列正在更新。如何正确执行此操作?

    1 回复  |  直到 2 年前
        1
  •  1
  •   Timeless    2 年前

    IIUC,您可以尝试:

    lcols = ["Year", "ID", "delivery", "type", "vendor"]
    rcols = ["Tags", "ID", "qtr", "TYPE", "msc"]
    
    out = (
        pd.merge(
            df_A, df_B,
            left_on=[*lcols, df_A.groupby(lcols).cumcount()],
            right_on=[*rcols, df_B.groupby(rcols).cumcount()],
            how="left"
        )
        .assign(project_id= lambda x: x["Project Name"].fillna(x["project_id"]))
        [df_A.columns]
    )
    

    输出:

    print(out)
    
       Year  ID delivery Gen type vendor             project_id
    0  2022  BR  Q2 2022   L   aa      d     BR2 H_AA01 Q2 2022
    1  2022  BR  Q2 2022   L   dd      d     BR2 H_DD01 Q2 2022
    2  2022  BR  Q2 2022   L   dd      d     BR2 H_DD02 Q2 2022
    3  2022  BR  Q3 2022   L   bb      d       BR2 BB01 Q3.2022
    4  2022  BR  Q4 2022   L   aa      d    BR2 aa1 Q4 2022 - L
    5  2022  BR  Q4 2022   L   dd     nd  BR2 H_DD_nd02 Q4 2022
    
    [6 rows x 7 columns]
    
        2
  •  1
  •   Nick SamSmith1986    2 年前

    您的问题是由于中的这两个条目引起的 df_A :

    2022    BR  Q2 2022 L   dd      d       BR2 dd1 Q2 2022 - L
    2022    BR  Q2 2022 L   dd      d       BR2 dd2 Q2 2022 - L
    

    和在 df_B :

    2022    BR  Q2 2022     L   dd      d       BR2 H_DD01 Q2 2022
    2022    BR  Q2 2022     L   dd      d       BR2 H_DD02 Q2 2022
    

    在合并中,这些具有完全相同的合并条件,因此您在输出中得到4行,而不是您想要的2行:

    1  2022  BR  Q2 2022   L   dd      d     BR2 H_DD02 Q2 2022
    2  2022  BR  Q2 2022   L   dd      d     BR2 H_DD01 Q2 2022
    3  2022  BR  Q2 2022   L   dd      d     BR2 H_DD02 Q2 2022
    4  2022  BR  Q2 2022   L   dd      d     BR2 H_DD01 Q2 2022
    

    没有任何进一步的识别手段 Project Name 在里面 df_B 对应于 project_id 在里面 df_A ,你将永远有这个问题。您可以使用解决此问题 drop_duplicates 例如

    df_final = df_final.drop_duplicates().reset_index(drop=True)
    

    这将给您:

       Year  ID delivery Gen type vendor             project_id
    0  2022  BR  Q2 2022   L   aa      d     BR2 H_AA01 Q2 2022
    1  2022  BR  Q2 2022   L   dd      d     BR2 H_DD02 Q2 2022
    2  2022  BR  Q2 2022   L   dd      d     BR2 H_DD01 Q2 2022
    3  2022  BR  Q3 2022   L   bb      d       BR2 BB01 Q3.2022
    4  2022  BR  Q4 2022   L   aa      d    BR2 aa1 Q4 2022 - L
    5  2022  BR  Q4 2022   L   dd     nd  BR2 H_DD_nd02 Q4 2022
    

    您也可以使用 cumcount 在@Timeless answer中提出的解决方案作为解决此问题的变通方法,但在任何一种情况下,您得到的结果都将取决于中的行的顺序 df_A 和 df_B 例如,如果行4&5英寸 df_B 被交换时,您将从他们的代码中获得以下输出:

    年份ID交付Gen类型供应商项目_ID
    0 2022 BR 2022 Q2 L aa d BR2 H_AA01 2022 Q2
    2022年1月BR 2022年第2季度L dd d BR2 H_DD02 2022年第二季度
    2022年2月BR 2022年第2季度L dd d BR2 H_DD01 2022年第二季度
    2022年3月BR 2022年第3季度L bb d BR2 BB01 2022年第三季度
    2022年4月BR 2022年第4季度L aa d BR2 aa1 2022年第四季度-L
    2022年5月BR 2022年第4季度L dd nd BR2 H_dd_nd02 2022年第四季度
    

    这可能对你的目的很好,但这是需要注意的。理想情况下,你应该有一些独特的东西来识别每个项目,并同时出现在这两个项目中 df_A 和 df_B (它可以像一个数字一样简单),否则你将来会继续遇到这个问题。