基于多索引的多个级别有效地连接两个数据帧

Cal*_*leb 9 python join pandas

我经常有一个带有大型多索引的数据帧,以及一个带有多索引的辅助DataFrame,它是较大索引的子集.辅助数据帧通常是某种查找表.我经常想要将查找表中的列添加到更大的数据帧中.主DataFrame通常非常大,所以我想有效地做到这一点.

这是一个虚构的例子,我想将df2加入到df1:

   In [11]: arrays = [    ['sun', 'sun', 'sun', 'moon', 'moon', 'moon', 'moon', 'moon'],
   ....:               ['summer', 'winter', 'winter', 'summer', 'summer', 'summer', 'winter', 'winter'],
   ....:               ['one', 'one', 'two', 'one', 'two', 'three', 'one', 'two']]

In [12]: tuples = list(zip(*arrays))

In [13]: index = pd.MultiIndex.from_tuples(tuples, names=['Body', 'Season','Item'])

In [14]: df1 = pd.DataFrame(np.random.randn(8,2), index=index,columns=['A','B'])

In [15]: df1
Out[15]:
                          A         B
Body Season Item
sun  summer one   -0.121588  0.272774
     winter one    0.233562 -2.005623
            two   -1.034642  0.315065
moon summer one    0.184548  0.820873
            two    0.838290  0.495047
            three  0.450813 -2.040089
     winter one   -1.149993 -0.498148
            two    2.406824 -2.031849

[8 rows x 2 columns]


In [16]: index2= pd.MultiIndex.from_tuples([('sun','summer'),('sun','winter'),('moon','summer'),('moon','winter')],names=['Body','Season'])

In [17]: df2 = pd.DataFrame(['Good','Bad','Ugly','Confused'],index=index2,columns = ['Mood'])

In [18]: df2
Out[18]:
                 Mood
Body Season
sun  summer      Good
     winter       Bad
moon summer      Ugly
     winter  Confused

[4 rows x 1 columns]
Run Code Online (Sandbox Code Playgroud)

现在,假设我想将df2中的列添加到df1中?这条线是我找到工作的唯一方法:

In [19]: df1 = df1.reset_index().join(df2,on=['Body','Season']).set_index(df1.index.names)

In [20]: df1
Out[20]:
                          A         B      Mood
Body Season Item
sun  summer one   -0.121588  0.272774      Good
     winter one    0.233562 -2.005623       Bad
            two   -1.034642  0.315065       Bad
moon summer one    0.184548  0.820873      Ugly
            two    0.838290  0.495047      Ugly
            three  0.450813 -2.040089      Ugly
     winter one   -1.149993 -0.498148  Confused
            two    2.406824 -2.031849  Confused

[8 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)

它有效,但这种方法存在两个问题.首先,这条线是丑陋的.需要重置索引,然后重新创建多索引,使这个简单的操作看起来不必要地复杂化.其次,如果我理解正确,每次运行reset_index()和set_index()时,都会创建一个数据帧的副本.我经常使用非常大的数据帧,这看起来非常低效.

有一个更好的方法吗?

Gio*_*Gio 10

我知道这是旧的,但加入 Pandas 1.0.3至少从 0.24 开始),允许合并具有部分匹配索引的 multiIndex 数据帧。

按照你的例子:

df1 = df1.join(df2, on=['Body','Season'])

Run Code Online (Sandbox Code Playgroud)


Jef*_*eff 6

这不是在ATM内部实现的,但是你的soln是推荐的,请看这里问题

如果你想让它看起来更漂亮,你可以简单地将它包装在一个函数中.reset_index/set_index复制(虽然你可以传递inplace=True参数,如果你想); 它确实在位,因为它们只是改变索引属性.

你可以修补一个很好的功能,如:

def merge_multi(self, df, on):
    return self.reset_index().join(df,on=on).set_index(self.index.names)
DataFrame.merge_multi = merge_multi

df1.merge_multi(df2,on=['Body','Season'])
Run Code Online (Sandbox Code Playgroud)

但是,按定义合并会创建新数据,因此不确定这实际上会为您节省多少.

更好的方法是构建更小的帧,然后进行更大的合并.你也可能想要做像这样

  • 在我最初的问题之后很久才意识到我从未选择过这个答案。我也想知道自这个答案以来是否已经开发出更好的规范解决方案,但我现在会给这个一个迟来的复选标记。 (3认同)
  • 还是这样吗? (2认同)