Використовуйте дані в кадрах даних панд, щоб разом узгодити стовпці


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.

Який найкращий спосіб зробити це?

Відповіді:


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'}

Дякую, що поділився гарною командою Енкі, чи не могли б ви пояснити детальніше [*df1.index]будь ласка? Будемо вдячні вам, ура.
RavinderSingh13

1
@ RavinderSingh13 Звичайно, sort_values(by=..)приймає список як параметр, тому я розпаковую індекс до списку тут, ви також можете зробити це list(df1.index)замість [*df1.index]:)
anky

16

Ось один із способів використання нумеру 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'}

1
Я засунув ніс у твій пост. Сподіваємось, ви не проти. Будь ласка, змініть його на свій смак.
піRSquared

А навпаки :) Хороший підхід, і перевірка великих фреймів даних трохи покращує продуктивність @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'}

Я подумав би додати ще одне розумне рішення, лише щоб побачити, що воно таке саме як ваше (-: 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'}

1
Як це, я можу зрозуміти кожен вираз у цих твердженнях, але не повністю бачу в голові, що насправді відбувається тут? Я як би шахи, я знаю, як перемістити всю частину на дошці, але не можу побачити більше, ніж 2 рухаються вперед.
Скотт Бостон

Гаразд ... Я це зараз перетравив, і це абсолютно просто, геніально. +1
Скотт Бостон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.