【问题标题】:Join on MultiIndex with different number of levels in pandas在 Pandas 中加入具有不同级别数的 MultiIndex
【发布时间】:2018-11-01 18:50:30
【问题描述】:

如何在 MultiIndex 上加入 2 个具有不同级别数的 pandas DataFrame?

import pandas as pd
t1 = pd.DataFrame(data={'a1':[0,0,1,1,2,2],
                        'a2':[0,1,0,1,0,1],
                        'x':[1.,2.,3.,4.,5.,6.]})
t1.set_index(['a1','a2'], inplace=True)
t1.sort_index(inplace=True)
t2 = pd.DataFrame(data={'b1':[0,1,2],
                        'y':[20.,40.,60.]})
t2.set_index(['b1'], inplace=True)
t2.sort_index(inplace=True)
>>> t1
         x
a1 a2     
0  0   1.0
   1   2.0
1  0   3.0
   1   4.0
2  0   5.0
   1   6.0
>>> t2
       y
b1      
0   20.0
1   40.0
2   60.0

加入 'a1' => 'b1' 的预期结果:

         x    y
a1 a2
0  0   1.0 20.0
   1   2.0 20.0
1  0   3.0 40.0
   1   4.0 40.0
2  0   5.0 60.0
   1   6.0 60.0

另一个例子:加入 ['a1','a2'] => ['b1','b2']:

import pandas as pd, numpy as np
t1 = pd.DataFrame(data={'a1':[0,0,0,0,1,1,1,1,2,2,2,2],
                        'a2':[3,3,4,4,3,3,4,4,3,3,4,4],
                        'a3':[7,8,7,8,7,8,7,8,7,8,7,8],
                        'x':[1.,2.,3.,4.,5.,6.,7.,8.,9.,10.,11.,12.]})
t1.set_index(['a1','a2','a3'], inplace=True)
t1.sort_index(inplace=True)
t2 = pd.DataFrame(data={'b1':[0,0,1,1,2,2],
                        'b2':[3,4,3,4,3,4],
                        'y':[10.,20.,30.,40.,50.,60.]})
t2.set_index(['b1','b2'], inplace=True)
t2.sort_index(inplace=True)
>>> t1
             x
a1 a2 a3   
0  3  7    1.0
      8    2.0
   4  7    3.0
      8    4.0
1  3  7    5.0
      8    6.0
   4  7    7.0
      8    8.0
2  3  7    9.0
      8   10.0
   4  7   11.0
      8   12.0
>>> t2
          y
b1 b2
0  3   10.0
   4   20.0
1  3   30.0
   4   40.0
2  3   50.0
   4   60.0

加入 ['a1','a2'] => ['b1','b2'] 的预期结果:

             x     y
a1 a2 a3         
0  3  7    1.0  10.0
      8    2.0  10.0
   4  7    3.0  20.0
      8    4.0  20.0
1  3  7    5.0  30.0
      8    6.0  30.0
   4  7    7.0  40.0
      8    8.0  40.0
2  3  7    9.0  50.0
      8   10.0  50.0
   4  7   11.0  60.0
      8   12.0  60.0

该解决方案应该在多个索引级别上工作。

感谢您的帮助!

【问题讨论】:

    标签: python pandas dataframe join multi-index


    【解决方案1】:

    第一个例子的解决方案:

    t1.reset_index('a2', drop=False).join(t2
        ).rename_axis('a1').set_index('a2', append=True)
    

    第二个例子的解决方案:

    t1.reset_index('a3', drop=False).join(
        t2.rename_axis(index={'b1':'a1', 'b2':'a2'})
        ).set_index('a3', append=True)
    

    【讨论】:

      【解决方案2】:

      您可以使用pd.Index.get_level_values 并映射来自t2 的系列:

      t1['y'] = t1.index.get_level_values(0).map(t2['y'].get)
      
      print(t1)
      
               x     y
      a1 a2           
      0  0   1.0  20.0
         1   2.0  20.0
      1  0   3.0  40.0
         1   4.0  40.0
      2  0   5.0  60.0
         1   6.0  60.0
      

      【讨论】:

      • 有没有办法修改这个解决方案,以便在 t1 有 3 个索引级别和 t2 有 2 个索引级别并且在 t2 的 2 个级别上完成连接时它可以工作?
      • @S.V,我相信这是可能的。但这应该作为一个单独的问题提出。
      【解决方案3】:

      您可以在t1 中名为a1 的索引级别上直接合并t1t2,以及t2 的单个索引:

      t1.merge(t2, left_on = t1.index.get_level_values('a1').values, right_index=True)
      
               x     y
      a1 a2           
      0  0   1.0  20.0
         1   2.0  20.0
      1  0   3.0  40.0
         1   4.0  40.0
      2  0   5.0  60.0
         1   6.0  60.0
      

      【讨论】:

        【解决方案4】:

        t2上使用reindex,适当设置level参数,直接赋值给t1

        t1['y'] = t2['y'].reindex(t1.index, level='a1')
        
                 x     y
        a1 a2           
        0  0   1.0  20.0
           1   2.0  20.0
        1  0   3.0  40.0
           1   4.0  40.0
        2  0   5.0  60.0
           1   6.0  60.0
        

        要在多个级别上重新索引,只需将列表作为 level 参数传递,例如['a1', 'a2'].

        【讨论】:

        • 这个解决方案看起来最有希望,因为它可能在 MultiIndex 中的多个级别上使用,但是如果我在第二个示例中使用它,我会得到以下结果(在 t2 中加入 2 个级别t1 有 3 个级别):即 t2['y'].reindex(t1.index, level=['a1','a2']) 给出 TypeError: Join on level between two MultiIndex objects is ambiguous.
        • reindex 不支持级别列表,只有一个级别,可悲的是:(
        【解决方案5】:

        在第二个示例中进行连接的缓慢方法:

        for col in t2.columns:
            for i2 in t2.index:
                t1.loc[i2+(slice(None),),col] = t2.loc[i2,col]
        

        任务是对其进行矢量化,并在创建 t1 索引项时自动将 slice(None) 放在正确的位置。

        第二个例子的矢量化版本:

        m = list(zip(t1.index.get_level_values('a1'), t1.index.get_level_values('a2')))
        t1 = t1.assign(**dict(zip(t2.columns,[np.nan]*len(t2.columns))))
        t1[t2.columns] = t2.loc[m,:].values
        

        第一个示例的矢量化版本:

        m = t1.index.get_level_values('a1')
        t1 = t1.assign(**dict(zip(t2.columns,[np.nan]*len(t2.columns))))
        t1[t2.columns] = t2.loc[m,:].values
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-03-12
          • 2020-02-14
          • 2020-09-16
          • 2019-02-16
          • 2018-11-09
          • 2019-01-18
          • 2013-01-22
          • 2017-04-19
          相关资源
          最近更新 更多