【问题标题】:Efficiently joining two dataframes based on multiple levels of a multiindex基于多索引的多个级别有效地连接两个数据帧
【发布时间】:2014-07-19 04:48:36
【问题描述】:

我经常有一个具有大型多索引的数据帧,以及一个具有多索引的辅助数据帧,它是较大的一个子集。辅助数据帧通常是某种查找表。我经常想将查找表中的列添加到更大的数据框中。主 DataFrame 通常非常大,所以我想高效地执行此操作。

这是一个虚构的例子,我在其中构造了两个数据框df1df2

import pandas as pd
import numpy as np

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']]

tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['Body', 'Season','Item'])
df1 = pd.DataFrame(np.random.randn(8,2), index=index,columns=['A','B'])

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

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

提供数据框:

df1

                    A         B
Body Season Item                     
sun  summer one   -0.409372  0.638502
     winter one    1.448772 -1.460596
            two   -0.495634 -0.839063
moon summer one    1.296035 -1.439349
            two   -1.002667  0.508394
            three -1.247748 -0.645782
     winter one   -1.848857 -0.858759
            two    0.559172  2.202957

df2

                 Mood
Body Season          
sun  summer      Good
     winter       Bad
moon summer      Ugly
     winter  Confused

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

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

导致:

           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() 时,都会创建一个数据帧的副本。我经常使用非常大的数据帧,这似乎非常低效。

有没有更好的方法来做到这一点?

【问题讨论】:

  • 您可以随时将inplace=True 传递给reset_index/set_index

标签: python join pandas


【解决方案1】:

join 现在允许将 MultiIndex DataFrames 与部分匹配的索引合并。

按照你的例子:

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

或者只是join而不使用on,默认情况下它将使用两个DataFrames之间的公共索引级别:

df1 = df1.join(df2)

结果df1:

                          A         B      Mood
Body Season Item                               
sun  summer one   -0.483779  0.981052      Good
     winter one   -0.309939  0.803862       Bad
            two   -0.413732  0.025331       Bad
moon summer one   -0.926068 -1.316808      Ugly
            two    0.221627 -0.226154      Ugly
            three  1.064856  0.402827      Ugly
     winter one    0.526461 -0.932231  Confused
            two   -0.296415 -0.812374  Confused

【讨论】:

  • @Caleb,也许你可以检查这个并更新答案。看起来不错。
【解决方案2】:

这不是在 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

【讨论】:

  • 还是这样吗?
  • 在我最初的问题之后很长时间才意识到我从未选择过这个问题的答案。我还想知道自从这个答案以来是否已经开发出任何更好的规范解决方案,但我现在会给这个一个迟来的复选标记。
猜你喜欢
  • 2018-06-24
  • 2019-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-15
  • 2020-09-18
  • 1970-01-01
  • 2017-09-04
相关资源
最近更新 更多