【问题标题】:Python Pandas: Merge or Filter DataFrame by Another. Is there a Better Way?Python Pandas:按另一个合并或过滤 DataFrame。有没有更好的办法?
【发布时间】:2015-11-02 17:20:25
【问题描述】:

我有时遇到的一种情况是,我有两个数据框(df1df2),我想根据df1 和@987654325 之间的多列的交集创建一个新的数据框(df3) @。

例如,我想通过按列CampaignGroup 过滤df1 来创建df3

import pandas as pd
df1 = pd.DataFrame({'Campaign':['Campaign 1', 'Campaign 2', 'Campaign 3', 'Campaign 3', 'Campaign 4'], 'Group':['Some group', 'Arbitrary Group', 'Group 1', 'Group 2', 'Done Group'], 'Metric':[245,91,292,373,32]}, columns=['Campaign', 'Group', 'Metric'])
df2 = pd.DataFrame({'Campaign':['Campaign 3', 'Campaign 3'], 'Group':['Group 1', 'Group 2'], 'Metric':[23, 456]}, columns=['Campaign', 'Group', 'Metric'])

df1

     Campaign            Group  Metric
0  Campaign 1       Some group     245
1  Campaign 2  Arbitrary Group      91
2  Campaign 3          Group 1     292
3  Campaign 3          Group 2     373
4  Campaign 4       Done Group      32

df2

     Campaign    Group  Metric
0  Campaign 3  Group 1      23
1  Campaign 3  Group 2     456

我知道我可以通过合并来做到这一点...

df3 = df1.merge(df2, how='inner', on=['Campaign', 'Group'], suffixes=('','_del'))
#df3
     Campaign    Group  Metric  Metric_del
0  Campaign 3  Group 1     292          23
1  Campaign 3  Group 2     373         456

但是我必须弄清楚如何drop_del 结尾的列。我猜是这样的:

df3.select(lambda x: not re.search('_del', x), axis=1)
##The result I'm going for but required merge, then select (2-steps)
     Campaign    Group  Metric
0  Campaign 3  Group 1     292
1  Campaign 3  Group 2     373

问题

我主要感兴趣的是返回df1,它只是根据df2Campaign|Group 值进行过滤。

  1. 有没有一种更好的方式来返回df1而不诉诸merge

  2. 有没有办法merge 但不将df2 的列返回到merge 并且只返回df1 的列?

【问题讨论】:

    标签: python pandas merge


    【解决方案1】:

    或者,您可以使用groupbyfilter,如下所示:

    # Compute the set of values you're interested in.
    # In your example, this will be {('Campaign 3', 'Group 1'), ('Campaign 3', 'Group 2')}
    interesting_groups = set(df2[['Campaign', 'Group']].apply(tuple, axis=1))
    # Filter df1, keeping only values in that set
    result = df1.groupby(['Campaign', 'Group']).filter(
        lambda x: x.name in interesting_groups
    )
    

    另一个例子见filter docs

    【讨论】:

      【解决方案2】:

      假设您的 df1df2 具有完全相同的列。您可以先将这些连接键列设置为索引,然后使用df1.reindex(df2.index) 和另一个.dropna() 来生成交集。

      df3 = df1.set_index(['Campaign', 'Group'])
      df4 = df2.set_index(['Campaign', 'Group'])
      # reindex first and dropna will produce the intersection
      df3.reindex(df4.index).dropna(how='all').reset_index()
      
           Campaign    Group  Metric
      0  Campaign 3  Group 1     292
      1  Campaign 3  Group 2     373
      

      编辑:

      当键不唯一时使用.isin

      # create some duplicated keys and values
      df3 = df3.append(df3)
      df4 = df4.append(df4)
      
      # isin
      df3[df3.index.isin(df4.index)].reset_index()
      
           Campaign    Group  Metric
      0  Campaign 3  Group 1     292
      1  Campaign 3  Group 2     373
      2  Campaign 3  Group 1     292
      3  Campaign 3  Group 2     373
      

      【讨论】:

      • 在上面的示例数据中,这很有效,但是当我将这个概念应用于我的真实数据集时,我得到Exception: cannot handle a non-unique multi-index!。我验证了df1df2 具有完全相同的列。关于原因以及如何解决的任何想法?
      • @Jarad 你可以尝试使用.isin 作为过滤规则,例如df3[df3.index.isin(df4.index)].reset_index()
      • 成功了。非常感谢李建勋的帮助。这个概念似乎是merge 的一个很好的替代方法。
      • @Jarad 不客气。很高兴它有帮助。 :-)
      猜你喜欢
      • 1970-01-01
      • 2014-02-06
      • 1970-01-01
      • 1970-01-01
      • 2021-07-29
      • 2013-01-10
      • 2021-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多