来自两个pandas数据框的记录不相交的集合

3
有没有一种简单的方法,可以基于MultiIndex在两个Pandas数据框之间找到不相交的记录集(即在结果内部连接中未包含的两个原始数据框中的内容)?
我是否遗漏了一些非常明显的东西,还是必须花费一些时间来实现这种功能?
我尝试通过查找两个数据框的muliIndex键集的对称差异来实现此操作,但这证明是困难的。我一直在努力让它工作。我的另一个选择似乎更容易一些,那就是添加一个整数的虚拟列,可以充当保留在我执行multiIndex合并后的不同单个键,以便我可以在这个事实上的单个键上使用Python set运算符。
[请注意,这与此问题相关,但略有不同,因为此合并不是基于MultiIndex对象,而是基于数据框列中的值:如何在两个Pandas DataFrame对象上执行SQL样式的不相交或集合差异?]
2个回答

1

使用TomAugspurger概述的相同测试数据

import pandas as pd
import numpy as np

# create a test data set
arrays1 = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
           ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]
arrays2 = [['bar', 'baz', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
           ['one', 'one', 'two', 'three', 'one', 'two', 'one', 'three']]
tuples1 = zip(*arrays1)
tuples2 = zip(*arrays2)
index1 = pd.MultiIndex.from_tuples(tuples1, names=['first', 'second'])
index2 = pd.MultiIndex.from_tuples(tuples2, names=['first', 'second'])
df1 = pd.DataFrame(np.random.randn(8, 2), index=index1)
df2 = pd.DataFrame(np.random.randn(8, 2), index=index2)

这将产生以下两个表格。
                     0         1
first second                    
bar   one    -0.579214  0.261575
      two     0.912683 -0.475463
baz   one    -0.295739 -0.586646
      two     0.031916  0.199812
foo   one    -0.724781 -1.245275
      two    -0.824759  2.270161
qux   one     0.638533  0.537306
      two    -0.988444 -1.076636

                     0         1
first second                    
bar   one    -0.859494  0.214814
baz   one    -0.446976  1.281912
      two    -0.181159  0.574126
      three   0.212799 -1.592317
foo   one    -1.192866  1.544799
      two     1.025816  0.921364
qux   one    -0.927700 -0.516720
      three   0.610065  0.028249

然后您可以通过以下方式获得不相交的数据框:

df1[~df1.index.isin(df2.index)].append(df2[~df2.index.isin(df1.index)])

导致结果为
                     0         1
first second                    
bar   two     0.912683 -0.475463
qux   two    -0.988444 -1.076636
baz   three   0.212799 -1.592317
qux   three   0.610065  0.028249

这就是你所要求的吗?


1
我认为你寻找对称差集的方法是正确的。
In [97]: from numpy import random

In [98]: arrays1 = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
   ....:           ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]


In [99]: arrays2 = [['bar', 'baz', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], [
   ....: 'one', 'one', 'two', 'three', 'one', 'two', 'one', 'three']]


In [100]: tuples1 = zip(*arrays1)

In [101]: tuples2 = zip(*arrays2)

In [102]: index1 = MultiIndex.from_tuples(tuples1, names=['first', 'second'])

In [103]: index2 = MultiIndex.from_tuples(tuples2, names=['first', 'second'])

In [104]: df1 = pd.DataFrame(random.randn(8, 2), index=index1)

In [105]: df2 = pd.DataFrame(random.randn(8, 2), index=index2)

In [106]: df1
Out[106]: 
                     0         1
first second                    
bar   one     0.613378 -0.400247
baz   one    -3.005834  0.004879
      two     0.066539 -0.289100
      three  -0.020099  0.644226
foo   one    -0.461458 -1.621812
      two     0.286655  0.110588
qux   one     0.363648 -0.271281
      three   1.707787 -1.832602

In [107]: df2
Out[107]: 
                     0         1
first second                    
bar   one    -1.010482 -0.023373
baz   one    -0.040335  1.553905
      two    -0.080283 -0.571686
      three  -0.985722 -0.795481
foo   one     0.623122  2.124316
      two    -0.493333 -0.343462
qux   one    -1.346753 -1.343945
      three  -0.053497 -0.382402

In [108]: sym_diff = (df1.index - df2.index).union(df2.index - df1.index)

In [109]: sym_diff
Out[109]: 
MultiIndex
[(u'baz', u'three'), (u'qux', u'three')]

我不确定为什么MultiIndex上没有对称差异方法。


好的,当我将第103行更改为index2并将第108行的最后一个术语更改为df1.index时,它可以工作。唯一的问题是由于MultiIndex和我的数据框的大小,计算sym_diff需要近一分钟的时间。我认为你的方法看起来更优雅,但我最终做的略有不同。在合并之前,我重新设置了索引,然后进行了两次合并,第一次保留了一个框架的索引,第二次保留了另一个框架的索引。然后,我按每个原始列中的索引删除了匹配的行。这是更多的代码,但只需要大约5秒钟的时间。 - Michael Discenza
我今天稍后会写出我的解决方案,以便任何人都可以看到。 - Michael Discenza
抱歉打错字了,你两个都是对的。很遗憾我的方法太慢了。你的索引提前排序了吗?我想知道这是不是花费最多时间的原因,还是集合操作。 - TomAugspurger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接