【问题标题】:How to keep column MultiIndex values when merging pandas DataFrames合并pandas DataFrames时如何保留列MultiIndex值
【发布时间】:2018-01-29 19:13:36
【问题描述】:

我有两个 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 列的名称?

【问题讨论】:

  • df1.assign(u=df1.ID.map(df2.set_index('item_id')['url'])) 适合你吗?
  • 它适用于这个例子,但在实际情况下,我在 df2 中有多个列,我想在连接中引入 - 所以我必须多次执行此操作才能获得每个专栏,我觉得不太理想。

标签: python pandas merge


【解决方案1】:

如果你不能打败他们,就加入他们。 (合并前让两个DataFrame的索引层数相同):

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

这也避免了UserWarning:

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

【讨论】:

    【解决方案2】:

    ID 的列不是“非分层的”。它由('ID', ) 表示。但是,pandas 允许您仅引用第一级列,其方式看起来像是在引用单级列结构。这意味着这应该适用于df1['ID'] 以及df1[('ID',)] 以及df1.loc[:, ('ID',)]。但如果碰巧顶级'ID' 在第二级有更多与之关联的列,df1['ID'] 将返回一个数据框。我对这个解决方案感觉更舒服,它看起来很像 @JohnGalt 在 cmets 中的回答。

    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
    

    【讨论】:

      【解决方案3】:

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

      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)
      

      【讨论】:

        猜你喜欢
        • 2019-08-27
        • 2018-11-11
        • 2018-10-19
        • 2020-06-15
        • 1970-01-01
        • 1970-01-01
        • 2018-07-22
        • 2018-06-25
        • 2020-11-30
        相关资源
        最近更新 更多