Usa i dati nei frame di dati Panda per abbinare le colonne


18

Ho due pandasframe di dati ae 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

e

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

I due frame di dati contengono esattamente gli stessi dati, ma in un ordine diverso e con nomi di colonna diversi. Sulla base dei numeri nei due frame di dati, vorrei essere in grado di abbinare il nome adi ogni colonna al nome di ciascuna colonna b.

Non è facile come semplicemente confrontare la prima riga di acon la prima riga di bcome ci sono valori duplicati, ad esempio entrambi a4e a7hanno il valore 5quindi non è possibile abbinarli immediatamente a uno b2o b4.

Qual è il modo migliore per farlo?

Risposte:


16

Ecco un modo usando 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'}

Grazie per aver condiviso il bel comando Anky, potresti per favore spiegare di più in [*df1.index]parte per favore? Ti sarò grato, evviva.
RavinderSingh13

1
@ RavinderSingh13 Certo, sort_values(by=..)accetta un elenco come parametro, quindi sto scompattando l'indice in un elenco qui, potresti anche fare list(df1.index)invece di [*df1.index]:)
ancora

16

Ecco un modo per sfruttare l'intorpidimento 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'}

Un altro approccio simile (di @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
Mi sono bloccato il naso nel tuo post. Spero non ti dispiaccia. Si prega di cambiarlo a proprio piacimento.
piRSquared

Ah al contrario :) Bel approccio, e controllando grandi frame di dati migliora leggermente le prestazioni @piRSquared
yatu

12

Un modo di 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'}

Ho pensato di aggiungere un'altra soluzione intelligente solo per vedere che era uguale al tuo (-: whoops.
piRSquared

8

comprensione del dizionario

Utilizzare uno tupledei valori di colonna come chiave hash in un dizionario

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

Nel caso in cui non abbiamo una rappresentazione perfetta, ho prodotto solo il dizionario per le colonne in cui esiste una corrispondenza.

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

Questo rasenta l'assurdo ... Non farlo davvero.

{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
Come mai, posso capire ogni espressione in queste affermazioni, ma non vedo completamente nella mia testa cosa sta realmente succedendo qui? Un po 'come gli scacchi, so come spostare tutto il pezzo sul tabellone, ma non riesco a vedere più di 2 che vanno avanti.
Scott Boston,

Okay ... L'ho digerito ora ed è assolutamente semplice, geniale. +1
Scott Boston,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.