2017-02-03 128 views
1

前面的问题:Pandas Compare two dataframes and determine the matched values比较两个dataframes和过滤匹配的值

我有两个dataframes:

print(a) 

    ID        Value 
0 AA12 101 BB101 CC01 DD06  1 
1 AA12 101 BB101 CC01 DD06  2 
2 AA11 102 BB101 CC01 2341 DD07 2 
3 AA10 202 BB101 CC01 3451 DD09 3 
4 AA13 103 BB101 CC02 1231  4 
5 AA14 203 BB101 CC02 4561  5 
print(b) 

    ID        Value 
0 AA12 101 BB101 CC01 1351 DD06 1 
1 AA12 101 BB101 CC01 1351 DD06 2 
2 AA11 102 BB101 CC01 DD07  2 
3 AA10 202 BB101 CC01 3451 DD09 3 
4 AA13 103 BB101 CC02    4 
5 AA14 203 BB101 CC02 4561  6 

所需的输出

 ID        Value ID Matched? Value Matched? 
0 AA12 101 BB101 CC01 DD06  1  Yes   Yes 
1 AA12 101 BB101 CC01 DD06  2  Yes   Yes 
2 AA11 102 BB101 CC01 2341 DD07 2  Yes   Yes 
3 AA10 202 BB101 CC01 3451 DD09 3  Yes   Yes 
4 AA13 103 BB101 CC02 1231  4  No   Yes 
5 AA14 203 BB101 CC02 4561  5  Yes   No 

这是一个被@MaxU编写的代码来自上一篇:

pd.merge(a.assign(x=a.ID.str.split().apply(sorted).str.join(' ')), 
      b.assign(x=b.ID.str.split().apply(sorted).str.join(' ')), 
      on=['x','Value'], 
      how='outer', 
      indicator=True) 

我想达到什么

  • 如果任dataframes不从[ 'ID'] 包含四位项(即2341,3451),我想从匹配过程中排除它。
  • 如果同一个ID出现多次,它们可以在 ['Value']上具有不同的值。

此代码的结果是here。不幸的是,它没有达到预期的结果。只有索引3匹配。我正在调整代码,但无法弄清下一步。

非常感谢您的时间和考虑!

+1

整个da taframe在ID中必须没有4位数字?或者你想只排除没有4位模式的行(如你的例子中的索引0和1)? – Boud

+0

如果a.ID或b.ID不包含4位数字,我想摆脱这些行上的ID。 – comproch

回答

1

试试这个:

首先,让我们分裂和堆栈两种话语结构ID列:

In [248]: d1 = df1.set_index('Value').ID.str.split(expand=True).stack().to_frame('ID').reset_index().rename(columns={'level_1':'idx'}) 
    ...: d2 = df2.set_index('Value').ID.str.split(expand=True).stack().to_frame('ID').reset_index().rename(columns={'level_1':'idx'}) 

In [249]: d1 
Out[249]: 
    Value idx  ID 
0  1 0 AA12 
1  1 1 101 
2  1 2 BB101 
3  1 3 CC01 
4  1 4 DD06 
5  2 0 AA12 
6  2 1 101 
7  2 2 BB101 
8  2 3 CC01 
9  2 4 DD06 
10  2 0 AA11 
11  2 1 102 
12  2 2 BB101 
13  2 3 CC01 
14  2 4 2341 
15  2 5 DD07 
16  3 0 AA10 
17  3 1 202 
18  3 2 BB101 
19  3 3 CC01 
20  3 4 3451 
21  3 5 DD09 
22  4 0 AA13 
23  4 1 103 
24  4 2 BB101 
25  4 3 CC02 
26  4 4 1231 
27  5 0 AA14 
28  5 1 203 
29  5 2 BB101 
30  5 3 CC02 
31  5 4 4561 

In [250]: d2 
Out[250]: 
    Value idx  ID 
0  1 0 AA12 
1  1 1 101 
2  1 2 BB101 
3  1 3 CC01 
4  1 4 1351 
5  1 5 DD06 
6  2 0 AA12 
7  2 1 101 
8  2 2 BB101 
9  2 3 CC01 
10  2 4 1351 
11  2 5 DD06 
12  2 0 AA11 
13  2 1 102 
14  2 2 BB101 
15  2 3 CC01 
16  2 4 DD07 
17  3 0 AA10 
18  3 1 202 
19  3 2 BB101 
20  3 3 CC01 
21  3 4 3451 
22  3 5 DD09 
23  4 0 AA13 
24  4 1 103 
25  4 2 BB101 
26  4 3 CC02 
27  6 0 AA14 
28  6 1 203 
29  6 2 BB101 
30  6 3 CC02 
31  6 4 4561 

现在我们可以搜索'not matched'编号:

In [251]: no_match_idx = d1.loc[~d1.ID.isin(d2.ID), 'idx'].unique() 

In [252]: no_match_idx 
Out[252]: array([4], dtype=int64) 

In [253]: df1['Matched_ID'] = ~df1.index.isin(no_match_idx) 
    ...: df1['Matched_Value'] = df1.Value.isin(df2.Value) 

结果:

In [254]: df1 
Out[254]: 
           ID Value Matched_ID Matched_Value 
0  AA12 101 BB101 CC01 DD06  1  True   True 
1  AA12 101 BB101 CC01 DD06  2  True   True 
2 AA11 102 BB101 CC01 2341 DD07  2  True   True 
3 AA10 202 BB101 CC01 3451 DD09  3  True   True 
4  AA13 103 BB101 CC02 1231  4  False   True 
5  AA14 203 BB101 CC02 4561  5  True   False 
+0

有史以来最好的解决方案!我也学习了堆叠!非常感谢您的时间和协助! – comproch

+1

@comprocho,很高兴我能帮忙:-) – MaxU