Verwenden Sie Daten in Pandas-Datenrahmen, um Spalten miteinander abzugleichen

18

Ich habe zwei pandasDatenrahmen aund 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

und

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

Die beiden Datenrahmen enthalten genau dieselben Daten, jedoch in unterschiedlicher Reihenfolge und mit unterschiedlichen Spaltennamen. Basierend auf den Zahlen in den beiden Datenrahmen möchte ich in der Lage sein, jeden Spaltennamen amit jedem Spaltennamen in abzugleichen b.

Es ist nicht so einfach, einfach die erste Zeile von amit der ersten Zeile von zu vergleichen, bda es doppelte Werte gibt, zum Beispiel beide a4und a7den Wert haben, 5so dass es nicht möglich ist, sie sofort mit entweder b2oder abzugleichen b4.

Was ist der beste Weg, dies zu tun?

OD1995
quelle

Antworten:

16

Hier ist ein Weg mit 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
quelle
Vielen Dank für das Teilen des netten Befehls Anky. Könnten Sie bitte zum [*df1.index]Teil mehr erklären ? Wird dir dankbar sein, Prost.
RavinderSingh13
1
@ RavinderSingh13 Sicher, sort_values(by=..)nimmt eine Liste als Parameter, also list(df1.index)[*df1.index]
entpacke
16

Hier ist eine Möglichkeit, Numpy zu nutzen 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'}

Ein anderer ähnlicher Ansatz (von @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
quelle
1
Ich habe meine Nase in deinen Beitrag gesteckt. Hoffentlich macht es dir nichts aus. Bitte ändern Sie es nach Ihren Wünschen.
piRSquared
Ah im Gegenteil :) Netter Ansatz, und die Überprüfung großer Datenrahmen verbessert die Leistung geringfügig @piRSquared
yatu
12

Ein Weg von 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
quelle
Ich dachte, ich würde eine weitere clevere Lösung hinzufügen, nur um zu sehen, dass es die gleiche ist wie deine (-: whoops.
piRSquared
8

Wörterbuchverständnis

Verwenden Sie einen tupleder Spaltenwerte als Hash-Schlüssel in einem Wörterbuch

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

Für den Fall, dass wir keine perfekte Darstellung haben, habe ich nur das Wörterbuch für Spalten erstellt, in denen eine Übereinstimmung vorliegt.

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

Das grenzt an das Absurde ... Tu das eigentlich nicht.

{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
quelle
1
Wie kommt es, dass ich jeden Ausdruck in diesen Aussagen verstehen kann, aber nicht vollständig in meinem Kopf sehe, was hier wirklich vor sich geht? Ein bisschen wie Schach, ich weiß, wie man die ganze Figur auf dem Brett bewegt, aber ich kann nicht mehr sehen, als 2 vorwärts zu bewegen.
Scott Boston
Okay ... ich habe das jetzt verdaut und es ist absolut einfach noch, brillant. +1
Scott Boston