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

时间:2014-05-29 15:49:09

标签: python join pandas

我经常拥有一个带有大型多索引的数据框,以及一个带有多索引的辅助数据框,该多索引是较大索引的子集。辅助数据帧通常是某种查找表。我经常想要将查找表中的列添加到更大的数据帧中。主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]

现在,假设我想将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]

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

有更好的方法吗?

2 个答案:

答案 0 :(得分:7)

我知道这很旧,但是join in Pandas 1.0.3(和at least since 0.24)允许合并具有部分匹配索引的multiIndex数据帧。

按照您的示例:

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

答案 1 :(得分:6)

这不是在ATM内部实施的,但推荐使用自己的解决方案,请参阅here以及issue

如果你想让它看起来更漂亮,你可以简单地将它包装在一个函数中。 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'])

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

更好的方法是构建更小的帧,然后进行更大的合并。您也可能想要执行this

之类的操作