【问题标题】:Merge DataFrames in Python without duplicating columns在 Python 中合并数据帧而不复制列
【发布时间】:2018-12-21 20:19:47
【问题描述】:

我正在尝试基于一个公共列合并几个 DataFrame。这将在循环中完成,原始 DataFrame 可能没有所有列,因此需要外部合并。但是,当我在几个不同的 DataFrames 列上执行此操作时,后缀 _x 和 _y 重复。我正在寻找一个 DataFrame,其中填充了数据,并且仅在以前不存在列时才添加列。

df1=pd.DataFrame({'Company Name':['A','B','C','D'],'Data1':[1,34,23,66],'Data2':[13,54,5354,443]})
      Company Name  Data1  Data2
0            A      1     13
1            B     34     54
2            C     23   5354
3            D     66    443

第二个 DataFrame,其中包含一些公司的附加信息:

pd.DataFrame({'Company Name':['A','B'],'Address':  ['str1', 'str2'], 'Phone': ['str1a', 'str2a']})

  Company Name Address  Phone
0            A    str1  str1a
1            B    str2  str2a

如果我想将这两者结合起来,它将使用 on=Column 成功合并为一个:

df1=pd.merge(df1,df2, on='Company Name', how='outer')

  Company Name  Data1  Data2 Address  Phone
0            A      1     13    str1  str1a
1            B     34     54    str2  str2a
2            C     23   5354     NaN    NaN
3            D     66    443     NaN    NaN

但是,如果我要在循环中再次执行相同的命令,或者如果我要与具有其他公司信息的另一个 DataFrame 合并,我最终会得到类似于以下内容的重复列:

df1=pd.merge(df1,pd.DataFrame({'Company Name':['C'],'Address':['str3'],'Phone':['str3a']}), on='Company Name', how='outer')
  Company Name  Data1  Data2 Address_x Phone_x Address_y Phone_y
0            A      1     13      str1   str1a       NaN     NaN
1            B     34     54      str2   str2a       NaN     NaN
2            C     23   5354       NaN     NaN      str3   str3a
3            D     66    443       NaN     NaN       NaN     NaN

当我真正想要的是一个具有相同列的 DataFrame 时,只需填充任何丢失的数据。

  Company Name  Data1  Data2 Address  Phone
0            A      1     13    str1  str1a
1            B     34     54    str2  str2a
2            C     23   5354    str3  str3a
3            D     66    443     NaN    NaN

提前致谢。我已经查看了之前在重复列中提出的问题以及对 Pandas 文档的审核,但没有任何进展。

【问题讨论】:

  • 我想你在找update
  • 更新仅在索引上对齐,该索引很可能不会相同,并且不允许更新不在原始 DataFrame 中的列。
  • @Epic_Test 可以尝试使用pd.merge(df1,df_other,how='outer').groupby('Company Name').first().reset_index()。这不是最有效的方法,但没有更多关于为什么要这样做的上下文,它应该足够好。例如,您能否首先连接循环中的所有其他数据帧,然后合并到df1,或者您需要在每个循环中更新df1 以执行任何代码?
  • @Ben.T 这与我正在寻找的完全一样。我正在解决它以确保没有任何意外的影响。如果您想将此作为答案,我将标记为已接受的答案。我可以接受这不是最有效的过程。我正在运行的循环需要我在迭代时添加到主 df,而不是一次完成所有操作,而且当时我不知道将发生多少次迭代或将出现哪些列。感谢您的帮助!

标签: python python-3.x pandas


【解决方案1】:

当您在一个循环中寻找合并一个数据框时,您可以通过以下方式执行此操作,即新数据框是否具有新公司名称,是否具有新列:

df1 = pd.DataFrame({'Company Name':['A','B','C','D'],
                    'Data1':[1,34,23,66],'Data2':[13,54,5354,443]})
list_dfo = [pd.DataFrame({'Company Name':['A','B'],
                          'Address':  ['str1', 'str2'], 'Phone': ['str1a', 'str2a']}),
            pd.DataFrame({'Company Name':['C'],'Address':['str3'],'Phone':['str3a']})]

for df_other in list_dfo:
    df1 = pd.merge(df1,df_other,how='outer').groupby('Company Name').first().reset_index()
    # and other code

在这个例子的最后:

print(df1)
 Company Name  Data1   Data2 Address  Phone
0            A    1.0    13.0    str1  str1a
1            B   34.0    54.0    str2  str2a
2            C   23.0  5354.0    str3  str3a
3            D   66.0   443.0     NaN    NaN

您可以使用first 而不是first,它会保留最后一个有效值,而不是每组每列中的第一个有效值,这取决于您需要的数据,来自df1 的数据还是来自df1 的数据来自df_other(如果有的话)。在上面的例子中,它没有改变任何东西,但是在下面的例子中你会看到:

#company A has a new address
df4 = pd.DataFrame({'Company Name':['A'],'Address':['new_str1']})

#first keep the value from df1
print(pd.merge(df1,df4,how='outer').groupby('Company Name')
        .first().reset_index())
Out[21]: 
  Company Name  Data1   Data2 Address  Phone
0            A    1.0    13.0    str1  str1a   #address is str1 from df1
1            B   34.0    54.0    str2  str2a
2            C   23.0  5354.0    str3  str3a
3            D   66.0   443.0     NaN    NaN

#while last keep the value from df4
print (pd.merge(df1,df4,how='outer').groupby('Company Name')
         .last().reset_index())
Out[22]: 
  Company Name  Data1   Data2   Address  Phone
0            A    1.0    13.0  new_str1  str1a   #address is new_str1 from df4
1            B   34.0    54.0      str2  str2a
2            C   23.0  5354.0      str3  str3a
3            D   66.0   443.0       NaN    NaN

【讨论】:

    【解决方案2】:

    IIUC,你可以试试这个;

    def update_df(df1, df_next):
        if 'Company Name' not in list(df1):
            pass
        else:
            df1.set_index('Company Name', inplace=True)
        df_next.set_index('Company Name', inplace=True)   
        new_cols = [item for item in set(df_next) if item not in set(df1)]
        for col in new_cols:
            df1['{}'.format(col)] = col
        df1.update(df_next) 
    
    update_df(df1, df2)
    update_df(df1, df3)
    df1
    
                  Data1  Data2  Address  Phone
    Company Name                              
    A                 1     13     str1  str1a
    B                34     54     str2  str2a
    C                23   5354     str3  str3a
    D                66    443  Address  Phone
    

    注1;为了能够使用df.update,您必须从set_index'Company Name',此函数将检查df1 一次,下一次将通过。添加的df 会将索引设置为'Company Name'

    注2;接下来,该函数将检查是否有新列,添加它们并填写列名(您可能想要更改它)。

    注3;最后你用你需要的值执行df.update

    【讨论】:

      猜你喜欢
      • 2018-05-06
      • 1970-01-01
      • 2020-04-10
      • 2021-07-07
      • 2021-11-23
      • 1970-01-01
      • 2022-11-29
      • 2016-10-17
      • 2020-05-16
      相关资源
      最近更新 更多