Используйте данные во фреймах данных pandas для сопоставления столбцов

18

У меня есть два pandasкадра данных, aи b:

a1   a2   a3   a4   a5   a6   a7
1    3    4    5    3    4    5
0    2    0    3    0    2    1
2    5    6    5    2    1    2

а также

b1   b2   b3   b4   b5   b6   b7
3    5    4    5    1    4    3
0    1    2    3    0    0    2
2    2    1    5    2    6    5

Два фрейма данных содержат абсолютно одинаковые данные, но в другом порядке и с разными именами столбцов. Основываясь на числах в двух фреймах данных, я хотел бы иметь возможность сопоставлять каждое имя столбца aс каждым именем столбца в b.

Это не так просто, как простое сравнение первой строки aс первой строкой, bпоскольку есть дублированные значения, например, оба a4и a7имеют значение, 5поэтому невозможно сразу сопоставить их с одним b2или с b4.

Каков наилучший способ сделать это?

OD1995
источник

Ответы:

16

Вот способ использования sort_values:

m=df1.T.sort_values(by=[*df1.index]).index
n=df2.T.sort_values(by=[*df2.index]).index
d=dict(zip(m,n))
print(d)

{'a1': 'b5', 'a5': 'b1', 'a2': 'b7', 'a3': 'b6', 'a6': 'b3', 'a7': 'b2', 'a4': 'b4'}
Анки
источник
Спасибо, что поделились хорошей командой Anky, не могли бы вы объяснить подробнее по [*df1.index]части, пожалуйста? Буду благодарен вам, ура.
RavinderSingh13
1
@ RavinderSingh13 Конечно, sort_values(by=..)принимает список в качестве параметра, поэтому я распаковываю индекс в список здесь, вы также можете сделать это list(df1.index)вместо [*df1.index]:)
anky
16

Вот один из способов использовать NumPy broadcasting:

b_cols = b.columns[(a.values == b.T.values[...,None]).all(1).argmax(1)]
dict(zip(a, b_cols))

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}

Еще один похожий подход (@piR):

a_ = a.to_numpy()
b_ = b.to_numpy()
i, j = np.where((a_[:, None, :] == b_[:, :, None]).all(axis=0))
dict(zip(a.columns[j], b.columns[i]))

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}
Yatu
источник
1
Я сунул нос в твой пост. Надеюсь, вы не против. Пожалуйста, измените его по своему вкусу.
piRSquared
А наоборот :) Хороший подход, и проверка на больших dataframes он немного повышает производительность @piRSquared
Yatu
12

Один из способов merge

s=df1.T.reset_index().merge(df2.T.assign(match=lambda x : x.index))
dict(zip(s['index'],s['match']))
{'a1': 'b5', 'a2': 'b7', 'a3': 'b6', 'a4': 'b4', 'a5': 'b1', 'a6': 'b3', 'a7': 'b2'}
YOBEN_S
источник
Я думал, что добавлю еще одно умное решение, только чтобы увидеть, что оно такое же, как у вас (-: whoops.
piRSquared
8

словарь пониманий

Использовать tupleзначения столбца в качестве хешируемого ключа в словаре

d = {(*t,): c for c, t in df2.items()}
{c: d[(*t,)] for c, t in df1.items()}

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}

На тот случай, если у нас нет идеального представления, я создал словарь только для столбцов, где есть совпадение.

d2 = {(*t,): c for c, t in df2.items()}
d1 = {(*t,): c for c, t in df1.items()}

{d1[c]: d2[c] for c in {*d1} & {*d2}}

{'a5': 'b1',
 'a2': 'b7',
 'a7': 'b2',
 'a6': 'b3',
 'a3': 'b6',
 'a1': 'b5',
 'a4': 'b4'}

idxmax

Это граничит с абсурдом ... На самом деле не делай этого.

{c: df2.T.eq(df1[c]).sum(1).idxmax() for c in df1}

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}
piRSquared
источник
1
Как же так, я могу понять каждое выражение в этих утверждениях, но не до конца увидеть в голове, что на самом деле происходит здесь? Вроде как в шахматы, я знаю, как переместить все фигуры на доске, но не вижу больше, чем 2 вперед.
Скотт Бостон
Хорошо ... Я переварил это сейчас, и это абсолютно просто, блестяще. +1
Скотт Бостон