Объединение панелей данных панд на 2 столбца, но в любом порядке - PullRequest
0 голосов
/ 22 мая 2018

Проблема:

У меня возникла ситуация с двумя кадрами:

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

Я бы хотел сделать слияние test2 с test1, где id_A == id_a и id_B == id_b ИЛИ , где 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

Текущее решение:

Мое решение работает, но кажетсягрязный, и я хотел бы посмотреть, пропускаю ли я какой-то более умный способ сделать что-то.Он включает в себя объединение test2 с самим собой, но изменение двух интересующих столбцов (id_a становится id_b и наоборот), а затем объединение оттуда.

test3 = pd.concat([test2, test2.rename(columns = {'id_a':'id_b', 'id_b':'id_a'})])

final_df = (test1.merge(test3, left_on = ['id_A', 'id_B'],
                        right_on = ['id_a', 'id_b'])
            .drop(['id_a', 'id_b'], axis=1))

Вопрос:

Кто-нибудь знает более аккуратный способ сделать это?Я чувствую, что, возможно, упускаю из виду какой-то удивительный, изумительный способ ведения дел.

Спасибо за вашу помощь!

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Вы можете сделать два внутренних соединения, затем объединить и удалить дубликаты, например:

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')
0 голосов
/ 23 мая 2018

С 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
0 голосов
/ 23 мая 2018

Можно попробовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...