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?

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

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

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

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.