Usar datos en marcos de datos de pandas para unir columnas


18

Tengo dos pandasmarcos de datos ay 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

y

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

Los dos marcos de datos contienen exactamente los mismos datos, pero en un orden diferente y con diferentes nombres de columna. Según los números en los dos marcos de datos, me gustaría poder hacer coincidir el nombre ade cada columna con el nombre de cada columna b.

No es tan fácil como simplemente comparando la primera fila de ala primera fila de bcomo valores duplicados, por ejemplo tanto a4y a7tiene el valor 5por lo que no es posible hacer coincidir inmediatamente a cualquiera b2o b4.

¿Cuál es la mejor manera de hacer esto?

Respuestas:


16

Aquí hay una manera de usar 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'}

Gracias por compartir el agradable comando Anky, ¿podrías explicar más en [*df1.index]parte, por favor? Te lo agradeceré, saludos.
RavinderSingh13

1
@ RavinderSingh13 Claro, sort_values(by=..)toma una lista como parámetro, así que estoy desempacando el índice a una lista aquí, también puedes hacerlo en list(df1.index)lugar de [*df1.index]:)
anky

16

Aquí hay una manera de aprovechar 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'}

Otro enfoque similar (por @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
Metí la nariz en tu publicación. Con suerte, no te importa. Por favor cámbialo a tu gusto.
piRSquared

Ah, por el contrario :) enfoque de Niza, y la comprobación de grandes tramas de datos que mejora el rendimiento ligeramente @piRSquared
Yatu

12

Una forma de 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'}

Pensé que agregaría otra solución inteligente solo para ver que era la misma que la tuya (-: whoops.
piRSquared

8

comprensión del diccionario

Utilice uno tuplede los valores de columna como la clave hashable en un diccionario

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

En caso de que no tengamos una representación perfecta, solo he producido el diccionario para las columnas donde hay una coincidencia.

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

Esto limita con lo absurdo ... En realidad, no hagas esto.

{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
¿Cómo es que puedo entender cada expresión en estas declaraciones, pero no puedo ver completamente en mi cabeza lo que realmente está pasando aquí? Algo así como el ajedrez, sé cómo mover toda la pieza en el tablero, pero no puedo ver más de 2 movimientos adelante.
Scott Boston

Bien ... He digerido esto ahora y es absolutamente simple todavía, brillante. +1
Scott Boston
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.