将pandas数据帧合并到2列但以任何顺序排列

时间:2018-05-22 20:55:05

标签: python pandas dataframe merge

问题:

我遇到了2个数据帧的情况:

test1 = pd.DataFrame({'id_A':['Ben', 'Julie', 'Jack', 'Jack'],
                  'id_B':['Julie', 'Ben', 'Nina', 'Julie']})

test2 = pd.DataFrame({'id_a':['Ben', 'Ben', 'Ben', 'Julie', 'Julie', 'Nina'],
                      'id_b':['Julie', 'Nina', 'Jack', 'Nina', 'Jack', 'Jack'],
                      'value':[1,1,0,0,1,0]})

>>> test1
    id_A   id_B
0    Ben  Julie
1  Julie    Ben
2   Jack   Nina
3   Jack  Julie

>>> test2
    id_a   id_b  value
0    Ben  Julie      1
1    Ben   Nina      1
2    Ben   Jack      0
3  Julie   Nina      0
4  Julie   Jack      1
5   Nina   Jack      0

我想要做的是将test2test1合并到id_A == id_aid_B == id_b ,其中{{1} }和id_A == id_b,产生以下数据框:

id_B == id_a

当前解决方案:

我的解决方案有效,但看起来很混乱,我想看看我是否会忽略一些更聪明的做事方式。它涉及将>>> final_df id_A id_B value 0 Ben Julie 1 1 Julie Ben 1 2 Jack Nina 0 3 Jack Julie 1 与其自身连接,但将感兴趣的2列(test2变为id_a,反之亦然),然后从那里合并。

id_b

问题:

有谁知道更简洁的方法吗?我觉得我可能会忽略一些令人惊讶的令人愉快的做事方式。

感谢您的帮助!

3 个答案:

答案 0 :(得分:2)

您可以尝试np.sort

test1.assign(key=pd.DataFrame(np.sort(test1.values,axis=1)).sum(1)).merge(test2.assign(key=pd.DataFrame(np.sort(test2[['id_a','id_b']].values,axis=1)).sum(1))).drop('key',1)
Out[188]: 
    id_A   id_B   id_a   id_b  value
0    Ben  Julie    Ben  Julie      1
1  Julie    Ben    Ben  Julie      1
2   Jack   Nina   Nina   Jack      0
3   Jack  Julie  Julie   Jack      1

答案 1 :(得分:2)

使用frozenset

test1.assign(
    value=test1.apply(frozenset, 1).map({frozenset(a): b for *a, b in test2.values}))

    id_A   id_B  value
0    Ben  Julie      1
1  Julie    Ben      1
2   Jack   Nina      0
3   Jack  Julie      1

不太可爱,更健壮。之后删除你需要的东西。

t1 = test1.assign(ref=list(map(frozenset, zip(test1.id_A, test1.id_B))))
t2 = test2.assign(ref=list(map(frozenset, zip(test2.id_a, test2.id_b))))

t1.merge(t2, on='ref')

    id_A   id_B            ref   id_a   id_b  value
0    Ben  Julie   (Julie, Ben)    Ben  Julie      1
1  Julie    Ben   (Julie, Ben)    Ben  Julie      1
2   Jack   Nina   (Jack, Nina)   Nina   Jack      0
3   Jack  Julie  (Jack, Julie)  Julie   Jack      1

答案 2 :(得分:1)

你可以做两个内连接,然后连接和去复制,如:

merge_1 = test1.merge(test2, left_on = ['id_A', 'id_B'], right_on= ['id_a', 'id_b'])
merge_2 = test1.merge(test2, left_on = ['id_A', 'id_B'], right_on= ['id_b', 'id_a'])
final_df = pd.concat([merge_1, merge_2]).drop_duplicates()

或者您可以执行外连接并手动计算条件:

final_df = test1.merge(test2, how='outer')
final_df = final_df[((final_df.id_A == final_df.id_a) &
                     (final_df.id_B == final_df.id_b)) |
                    ((final_df.id_A == final_df.id_b) &
                     (final_df.id_B == final_df.id_a))]

或者您可以创建一个始终按照已知顺序的联接键:

test1['join_key'] = test1.apply(lambda row: tuple(sorted(row[['id_A', 'id_B']])), axis=1)
test2['join_key'] = test2.apply(lambda row: tuple(sorted(row[['id_a', 'id_b']])), axis=1)
final_df = test1.merge(test2, on='join_key').drop('join_key')