您如何根据特定的键值对比较两个熊猫系列?

时间:2020-06-29 15:33:37

标签: python pandas

我有2个pandas系列字典,如下所示:

series_1 = [{'id': 'testProd_1', 'q1':'Foo1', 'q2': 'Bar1'},
            {'id': 'testProd_2', 'q1':'Foo2', 'q2': 'Bar2'},
            {'id': 'testProd_3', 'q1':'Foo3', 'q2': 'Bar3'},
            {'id': 'testProd_5', 'q1':'Foo5', 'q2': 'Bar5'}
 ]
series_2 = [{'q1':'Foo1', 'q2': 'Bar1'},
            {'q1':'Foo2', 'q2': 'Bar2'}, 
            {'q1':'Foo3', 'q2': 'Bar3'}, 
            {'q1':'Foo4', 'q2': 'Bar4'}, 
            {'q1':'Foo5', 'q2': 'Bar{5}'}]

我正在尝试比较两个熊猫系列,并将series_1的ID提供给所有匹配的series_2字典。

expected_result = [{'id': 'testProd_1', 'q1':'Foo1', 'q2': 'Bar1'},
                   {'id': 'testProd_2', 'q1':'Foo2', 'q2': 'Bar2'},
                   {'id': 'testProd_3', 'q1':'Foo3', 'q2': 'Bar3'},
                   {'id': 'testProd_5', 'q1':'Foo5', 'q2': 'Bar{5}'}]

等值序列无效,因为一个序列对每个字典有一个附加的键值对('id')。我是否必须遍历每个单独的条目?什么是获得Expected_result的最有效方法?

我正在使用2个大型数据集,试图将ID从一个系列链接到另一个系列。数据基本相同,但有时某些键值对中的值具有一些错误的字符(例如:{5},(5),{ex.5})。

有什么建议吗?

谢谢

3 个答案:

答案 0 :(得分:1)

因此,似乎您要使用的是merge。据我了解,您想在“ q1”键上找到两个数据框的内部联接。如果是这样,那么合并绝对是适合您的功能。它的使用方式如下:

series_join = series_1.merge(series_2, on='q1')

这样,它将找到q1的交集,并且仅选择匹配的数据对。如果您确实想同时加入q1q2,则可以在此处简单地传递一个数组(尽管这样无法提供所需的输出,因为无法比较Bar5Bar{5},很遗憾:

series_join = series_1.merge(series_2, on=['q1', 'q2'])

至于从数据中清除错误值以便可以通过这种方式进行比较,我建议首先执行清除步骤,因为主要合并步骤对如何比较数据值没有太多定制。

输出将包含一组重复的列,但是无论如何您都可以忽略这些列:

           id    q1  q2_x    q2_y
0  testProd_1  Foo1  Bar1    Bar1
1  testProd_2  Foo2  Bar2    Bar2
2  testProd_3  Foo3  Bar3    Bar3
3  testProd_5  Foo5  Bar5  Bar{5}

在这里运行repl

编辑:保留重复

默认的合并功能是将所有重复的键保留在两个表中。此处操作重复项的问题是,熊猫不知道哪一行是预期的查找行,因此它只会为每种组合创建一对。如下例所示(系列1、2,然后加入):

           id    q1    q2
0  testProd_1  Foo1  Bar1
1  testProd_2  Foo2  Bar2
2  testProd_3  Foo3  Bar3
3  testProd_5  Foo5  Bar5
4  testProd_6  Foo5  Bar6
     q1      q2
0  Foo1    Bar1
1  Foo2    Bar2
2  Foo3    Bar3
3  Foo4    Bar4
4  Foo5  Bar{5}
5  Foo5  Bar{6}
           id    q1    q2_y
0  testProd_1  Foo1    Bar1
1  testProd_2  Foo2    Bar2
2  testProd_3  Foo3    Bar3
3  testProd_5  Foo5  Bar{5} <<< [3  testProd_5  Foo5  Bar5] + [4  Foo5  Bar{5}]
4  testProd_5  Foo5  Bar{6} <<< [3  testProd_5  Foo5  Bar5] + [5  Foo5  Bar{6}]
5  testProd_6  Foo5  Bar{5} <<< [4  testProd_6  Foo5  Bar6] + [4  Foo5  Bar{5}]
6  testProd_6  Foo5  Bar{6} <<< [4  testProd_6  Foo5  Bar6] + [5  Foo5  Bar{6}]

因此,没有一种简单的方式说“选择第二张表的第一行”,但是您可以做的就是简单地使用drop_duplicates之类的函数预先删除第二张表中的重复项。 / p>

答案 1 :(得分:1)

您可以像这样使用熊猫:

pd.DataFrame(series_1)[['id','q1']].merge(pd.DataFrame(series_2), on=['q1']).to_dict('records')

输出:

[{'id': 'testProd_1', 'q1': 'Foo1', 'q2': 'Bar1'},
 {'id': 'testProd_2', 'q1': 'Foo2', 'q2': 'Bar2'},
 {'id': 'testProd_3', 'q1': 'Foo3', 'q2': 'Bar3'},
 {'id': 'testProd_5', 'q1': 'Foo5', 'q2': 'Bar{5}'}]

使用有问题的新数据更新

大熊猫将为1对多连接或多对多连接创建笛卡尔乘积。因此,您将进行组合。

df1.merge(df2, on=['q1'])

输出:

           id    q1  q2_x    q2_y
0  testProd_1  Foo1  Bar1    Bar1
1  testProd_2  Foo2  Bar2    Bar2
2  testProd_3  Foo3  Bar3    Bar3
3  testProd_5  Foo5  Bar5  Bar{5}
4  testProd_5  Foo5  Bar5  Bar{6}
5  testProd_6  Foo5  Bar6  Bar{5}
6  testProd_6  Foo5  Bar6  Bar{6}

无重复

没有重复项,您可以创建一个累加计,这样第一行就可以与df2中的第一行相连,如下所示:

df1m = df1.assign(mergekey=df1.groupby('q1').cumcount())
df2m = df2.assign(mergekey=df2.groupby('q1').cumcount())
df1m.merge(df2m, on=['q1','mergekey'])

输出:

           id    q1  q2_x  mergekey    q2_y
0  testProd_1  Foo1  Bar1         0    Bar1
1  testProd_2  Foo2  Bar2         0    Bar2
2  testProd_3  Foo3  Bar3         0    Bar3
3  testProd_5  Foo5  Bar5         0  Bar{5}
4  testProd_6  Foo5  Bar6         1  Bar{6}

答案 2 :(得分:0)

感谢所有反馈。

我结合了以上答案,得出了对我有用的解决方案。

series_2的q1和q2值过多,且字符错误(例如:'{','。','}',等等。)以及大小写混合。

我首先应用了apply来将值全部清除为小写并使用replace删除特殊字符。

# Creates a uniform value string 
def getTrueString(valString):
    
    trueString= valString.lower()
    remove_specialChrs = [' ','{','}','ex.']
    
    for char in remove_specialChrs:
        trueString= trueString.replace(char,'')
            
    return trueString.strip()

从那里开始,我将其应用于我的2个系列(假设我已转换为数据帧)

series_1['trueString'] = series_1['valString'].apply(getTrueString)
series_2['trueString'] = series_2['valString'].apply(getTrueString)

现在,由于trueString是干净的(小写字母和所有特殊字符都已删除),因此我按照上面的帖子中Scott Scott和Daneolog的建议使用了熊猫合并。

joined_data = pd.merge(series_2, series_1, on='trueString', how='left' )

结果数据框显示基于trueString的所有匹配项,对于不匹配的结果,将保持为空。这是因为我选择了左联接(您也可以使用right并切换2个输入帧)而不是用内部联接,因为我想查看所有series_2数据,而不管是否找到id。

希望这会有所帮助。