【问题标题】:Joining two dfs based on different col names? [duplicate]根据不同的列名加入两个dfs? [复制]
【发布时间】:2020-04-03 10:43:03
【问题描述】:

我有两个数据框,例如:

dfa:
Name  |   ID   |   Amount
Bob      V434      50.00
Jill     B333      22.11
Hank     B442      11.11

dfb:
Name | ID_First | ID_Second | ID_Third
Bob      V434      E333        B442
Karen    V434      E333        B442
Jill     V434      E333        B442
Hank     V434      E333        B442

我想将dfa加入dfb,但是dfa中的ID只对应dfb中的IDS之一。

有没有办法我可以在dfa 中将dfa 加入dfadfb,所以基本上如果它匹配dfb 中的任何ID,那么我可以匹配来自dfa 的金额?

所需的输出只是:

Name | ID_First | ID_Second | ID_Third | Amount 
    Bob      V434      E333        B442     50.00
    Jill    V434      E333        B442      22.11
    Hank     V434      E333        B442     11.11

基本上加入两个表中都存在的名称,但存在于dfa 中的ID 仅存在于dfb 之一下的ID_First,第二或第三列,因此匹配相同的数量名称和相同的 ID 值,但该 ID 值仅在 IDS 中的 dfb 之一中。

谢谢

【问题讨论】:

  • 你能澄清一下你想要做什么吗?
  • 添加所需的输出
  • 55.00 的数量来自哪里以及为什么 Jill 也没有在所需的输出中列出?
  • 我们假设名称是唯一的吗? ID 似乎不是唯一的,因此合并它们会有问题。另外,您是否只想在最终输出中从 dfa 中删除 ID 列?
  • 是的,名字是唯一的,输出只是一个例子,而不是真实的确切数据

标签: python python-3.x pandas inner-join


【解决方案1】:

您可以尝试对所有三个进行合并,但不确定这样做的效率如何。如果可能的话,当您跨 ID 有多个匹配项时,这将不起作用。以下可能有效;

new_df = pd.DataFrame()
for col in ['ID_First', 'ID_Second', 'ID_Third']:
  df = pd.merge(dfa, dfb, left_on='ID', right_on=col, how='left')
  new_df = df if new_df.empty else new_df.append(df)

我认为您不能在 pd.merge 中使用“或”条件。

这是另一种可能性;

Python Pandas: How to merge based on an "OR" condition?

【讨论】:

    【解决方案2】:

    您可以对每个 id 列进行 3 个内部连接并将它们连接起来

    df1 = pd.DataFrame([['Bob','V434',50.00],['Jill','E333',22.11],['Hank','B442',11.11]],
                       columns=['Name','ID','Amount'])
    
    df2 = pd.DataFrame([['Bob','V434','E333','B442'],
                        ['Karen','V434','E333','B442'],
                        ['Jill','V434','E333','B442'],
                        ['Hank','V434','E333','B442']],
                       columns=['Name','ID_First','ID_Second','ID_Third'])
    
    print(pd.concat([df1.merge(df2, left_on=['ID','Name'], right_on=['ID_First','Name']),
                     df1.merge(df2, left_on=['ID', 'Name'], right_on=['ID_Second', 'Name']),
                     df1.merge(df2, left_on=['ID', 'Name'], right_on=['ID_Third', 'Name'])])[['Name','ID','Amount']])
    

    输出:

       Name    ID  Amount
    0   Bob  V434   50.00
    0  Jill  E333   22.11
    0  Hank  B442   11.11
    

    即兴发挥@Ian 的答案以获得所需的输出:

    new_df = pd.DataFrame()
    for col in ['ID_First', 'ID_Second', 'ID_Third']:
      df = pd.merge(df1, df2, left_on=['ID','Name'], right_on=[col,'Name'], how='inner')
      new_df = df if new_df.empty else new_df.append(df)
    

    【讨论】:

      【解决方案3】:

      解决方案

      您可以使用简单的merge 语句来完成此操作,如下所示。

      pd.merge(dfa[['Name', 'Amount']], dfb, how='inner', on='Name')
      

      注意:在合并 dfadfb 时,dfa.IDdfb.ID不像主键,它们的值也不是独特。这里唯一重要的是 inner join dfadfb 使用 "Name" 列。

      输出

      为了重现性

      您可以使用以下代码块加载数据并测试上面给出的解决方案

      import numpy as np
      import pandas as pd
      from io import StringIO
      
      # Example Data
      dfa = """
      Name  |   ID   |   Amount
      Bob   |  V434  |   50.00
      Jill  |  B333  |   22.11
      Hank  |  B442  |   11.11
      """
      dfb = """
      Name  | ID_First | ID_Second | ID_Third
      Bob   |  V434    | E333      | B442
      Karen |  V434    | E333      | B442
      Jill  |  V434    | E333      | B442
      Hank  |  V434    | E333      | B442
      """
      
      # Load Data and Clean up empty spaces 
      # in headers and columns
      dfa = pd.read_csv(StringIO(dfa), sep='|')
      dfb = pd.read_csv(StringIO(dfb), sep='|')
      dfa.columns = dfa.columns.str.strip()
      dfb.columns = dfb.columns.str.strip()
      for col in dfa.columns:
          if col=='Amount':
              dfa[col] = dfa[col].astype(str).str.strip().astype(float)
          else:    
              dfa[col] = dfa[col].str.strip()
      for col in dfb.columns:
          dfb[col] = dfb[col].str.strip()
      
      # merge dfa and dfb: Note that dfa.ID and dfb.ID do not act 
      # like primary keys, neither are their values unique. 
      # The only thing that matters here is to inner join dfa 
      # and dfb using the "Name" column.  
      
      pd.merge(dfa[['Name', 'Amount']], dfb, how='inner', on='Name')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-02
        • 1970-01-01
        • 1970-01-01
        • 2021-10-24
        • 1970-01-01
        • 1970-01-01
        • 2020-09-16
        • 2022-12-07
        相关资源
        最近更新 更多