条件多列匹配(使用新示例查看)

时间:2013-09-03 22:33:20

标签: python pandas matching

我试图重新设计我的问题,以符合质量标准,并花更多时间试图自己实现结果。

给出两个DataFrame

a = DataFrame({"id" : ["id1"] * 3 + ["id2"] * 3 + ["id3"] * 3,
               "left" : [6, 2, 5, 2, 1, 4, 5, 2, 4],
               "right" : [1, 3, 4, 6, 5, 3, 6, 3, 2]               
             })

b = DataFrame({"id" : ["id1"] * 6 + ["id2"] * 6 + ["id3"] * 6,
               "left_and_right" : range(1,7) * 3,  
               "boolen" : [0, 0, 1, 0, 1, 0, 1, 0, 0 , 1, 1, 0, 0, 0, 1, 0, 0, 1]
             })

预期结果是

result = DataFrame({"id" : ["id1"] * 3 + ["id2"] * 3 + ["id3"] * 3,
                    "left"  : [6, 2, 5, 2, 1, 4, 5, 2, 4],
                    "right"  : [1, 3, 4, 6, 5, 3, 6, 3, 2],
                    "NEW": [0, 1, 1, 0, 1, 1, 1, 1, 0]               
                  })

所以我想检查DataFrame b的每一行,如果DataFrame中有一行a aid == b.id然后查找b.left_and_right是否在(==)a.left或者a .rigtht。
如果找到这样的行并且对于a.left或a.right的值,b.boolen为True / 1,则该行中a.NEW的值也应为True / 1。

我希望这个例子比我的话更好地说明了它。

总结一下:我想查找两个数据框中id是否相同的每一行是否b.boolen为真/ 1表示b.left_and_right中的值,如果此值为a.left或在a.right中,a.NEW中的新值也应为TRUE / 1.

我尝试将pd.match()和pd.merge()函数与&组合使用和|运营商但无法达到想要的结果。

前段时间我曾经问过一个非常类似的问题来处理R中的simillar问题(数据是以稍微不同的方式组织的,所以它有点不同)但现在我在python中使用相同的方法失败了。
相关问题:Conditional matching of two lists with multi-column data.frames

由于

1 个答案:

答案 0 :(得分:3)

只需使用带&的布尔掩码(和)和| (或):

In [11]: (a.A == b.A) & ((a.B == b.E) | (a.C == b.E)) # they all satisfy this requirement!
Out[11]: 
0    True
1    True
2    True
3    True
dtype: bool

In [12]: b.D[(a.A == b.A) & ((a.B == b.E) | (a.C == b.E))]
Out[12]: 
0    0
1    1
2    0
3    0
Name: D, dtype: int64

In [13]: a['NEW'] = b.D[(a.A == b.A) & ((a.B == b.E) | (a.C == b.E))]

In [14]: a
Out[14]: 
     A  B  C  NEW
0  foo  1  4    0
1  goo  2  3    1
2  doo  3  1    0
3  boo  4  2    0

使用略有不同的问题进行更新:

In [21]: merged = pd.merge(a, b, on='id')

In [22]: matching = merged[(merged.left == merged.left_and_right) | (merged.right == merged.left_and_right)]

In [23]: (matching.groupby(['id', 'left', 'right'])['boolen'].sum()).reset_index()
Out[23]: 
    id  left  right  boolen
0  id1     2      3       1
1  id1     5      4       1
2  id1     6      1       0
3  id2     1      5       2
4  id2     2      6       0
5  id2     4      3       1
6  id3     2      3       1
7  id3     4      2       0
8  id3     5      6       1

注意这里有一个2,所以也许你想关心那些> 0

In [24]: (matching.groupby(['id', 'left', 'right'])['boolen'].sum() > 0).reset_index()
Out[24]: 
    id  left  right boolen
0  id1     2      3   True
1  id1     5      4   True
2  id1     6      1  False
3  id2     1      5   True
4  id2     2      6  False
5  id2     4      3   True
6  id3     2      3   True
7  id3     4      2  False
8  id3     5      6   True

您可能希望将boolen列重命名为NEW。