合并pandas DataFrames

时间:2017-08-21 16:20:54

标签: python pandas merge

我有两个pandas DataFrame,如下所示:

df1 = pd.DataFrame({('Q1', 'SubQ1'):[1, 2, 3], ('Q1', 'SubQ2'):[1, 2, 3], ('Q2', 'SubQ1'):[1, 2, 3]})
df1['ID'] = ['a', 'b', 'c']

df2 = pd.DataFrame({'item_id': ['a', 'b', 'c'], 'url':['a.com', 'blah.com', 'company.com']})

df1

     Q1          Q2 ID
  SubQ1 SubQ2 SubQ1   
0     1     1     1  a
1     2     2     2  b
2     3     3     3  c

df2

  item_id          url
0       a        a.com
1       b     blah.com
2       c  company.com

请注意,df1有一些带有层次索引的列(例如('Q1', 'SubQ1')),有些列只有正常的索引(例如。ID)。

我想在IDitem_id字段上合并这两个数据框。使用:

result = pd.merge(df1, df2, left_on='ID', right_on='item_id')

给出:

   (Q1, SubQ1)  (Q1, SubQ2)  (Q2, SubQ1) (ID, ) item_id          url
0            1            1            1      a       a        a.com
1            2            2            2      b       b     blah.com
2            3            3            3      c       c  company.com

正如您所看到的,合并本身工作正常,但MultiIndex已丢失并已恢复为元组。我尝试使用pd.MultiIndex.from_tuples重新创建MultiIndex,如:

result.columns = pd.MultiIndex.from_tuples(result)

但这会导致item_idurl列出现问题,只会使用其名称的前两个字符:

     Q1          Q2 ID  i            u
  SubQ1 SubQ2 SubQ1     t            r
0     1     1     1  a  a        a.com
1     2     2     2  b  b     blah.com
2     3     3     3  c  c  company.com

df2中的列转换为单元素元组(即。('item_id',)而不仅仅是'item_id')没有任何区别。

如何合并这两个DataFrame并正确保存MultiIndex?或者,我如何获取合并的结果并使用正确的MultiIndex返回列,而不会弄清item_idurl列的名称?

3 个答案:

答案 0 :(得分:5)

如果你无法击败他们,请加入他们。 (在合并之前,使两个DataFrames具有相同数量的索引级别):

    Test_Image,Original_Size
    red-room.png,918394
    Q,S,B,S,C,R
    0,1021763,0.121086,0.00001459,-11.26,-222.18
    1,1061763,0.125086,0.00001459,-11.26,-222.18
    2,1051763,0.121086,0.00001459,-11.26,-222.18
    3,1041763,0.121086,0.00001459,-11.26,-222.18
    4,986461,0.151573,0.00003318,-7.63,-211.67
    5,955766,0.160869,0.00005782,-4.07,-201.37

产量

import pandas as pd

df1 = pd.DataFrame({('Q1', 'SubQ1'):[1, 2, 3], ('Q1', 'SubQ2'):[1, 2, 3], ('Q2', 'SubQ1'):[1, 2, 3]})
df1['ID'] = ['a', 'b', 'c']

df2 = pd.DataFrame({'item_id': ['a', 'b', 'c'], 'url':['a.com', 'blah.com', 'company.com']})

df2.columns = pd.MultiIndex.from_product([df2.columns, ['']])
result = pd.merge(df1, df2, left_on='ID', right_on='item_id')
print(result)

这也避免了 Q1 Q2 ID item_id url SubQ1 SubQ2 SubQ1 0 1 1 1 a a a.com 1 2 2 2 b b blah.com 2 3 3 3 c c company.com

  

pandas / core / reshape / merge.py:551:UserWarning:在不同级别之间合并会产生意想不到的结果(左边2个级别,右边1个)

答案 1 :(得分:1)

ID的列不是"非等级"。它由('ID', )表示。但是,pandas允许您以一种看起来像引用单个水平列结构的方式仅引用第一级列。这意味着它应该df1['ID']以及df1[('ID',)]以及df1.loc[:, ('ID',)]。但如果恰好是顶级'ID'在第二级中有更多与之关联的列,df1['ID']将返回一个数据帧。我对这个解决方案感到更舒服,这看起来很像@ JohnGalt在评论中给出的答案。

df1.assign(u=df1[('ID', '')].map(df2.set_index('item_id').url))

     Q1          Q2 ID            u
  SubQ1 SubQ2 SubQ1                
0     1     1     1  a        a.com
1     2     2     2  b     blah.com
2     3     3     3  c  company.com

将单个级别的列和数据帧连接到多级列数据帧很困难。我必须人为地添加另一个级别。

def rnm(d):
    d = d.copy()
    d.columns = [d.columns, [''] * len(d.columns)]
    return d

df1.join(rnm(df2.set_index('item_id')), on=('ID',))

     Q1          Q2 ID          url
  SubQ1 SubQ2 SubQ1                
0     1     1     1  a        a.com
1     2     2     2  b     blah.com
2     3     3     3  c  company.com

答案 2 :(得分:0)

此解决方案更加灵活,因为您无需在concat之前插入列级别,可以使用它来连接任意数量的级别:

import pandas as pd

df1 = pd.DataFrame({('A', 'b'): [1, 2], ('A', 'c'): [3, 4]})

df2 = pd.DataFrame({'Zaa': [1, 2]})

df3 = pd.DataFrame({('Maaa', 'k', 'l'): [1, 2]})

df = pd.concat([df1, df2, df3], axis=1)
cols = [col if isinstance(col, tuple) else (col, ) for col in df.columns]
df.columns = pd.MultiIndex.from_tuples(cols)