Utilisez des données dans des blocs de données pandas pour faire correspondre les colonnes ensemble


18

J'ai deux pandastrames de données aet 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

et

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

Les deux trames de données contiennent exactement les mêmes données, mais dans un ordre différent et avec des noms de colonne différents. Sur la base des nombres dans les deux trames de données, je voudrais pouvoir faire correspondre chaque nom de colonne dedans aà chaque nom de colonne dedans b.

Ce n'est pas aussi simple que de comparer simplement la première ligne de aavec la première ligne bcar il y a des valeurs dupliquées, par exemple les deux a4et a7ont la valeur 5il n'est donc pas possible de les faire correspondre immédiatement à l'un b2ou à l'autre b4.

Quelle est la meilleure façon de procéder?

Réponses:


16

Voici un moyen d'utiliser 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'}

Merci de partager la belle commande Anky, pourriez-vous s'il vous plaît expliquer plus sur la [*df1.index]partie s'il vous plaît? Je vous en serai reconnaissant.
RavinderSingh13

1
@ RavinderSingh13 Bien sûr, sort_values(by=..)prend une liste en tant que paramètre, donc je décompresse l'index dans une liste ici, vous pouvez également le faire à la list(df1.index)place de [*df1.index]:)
anky

16

Voici une façon d'exploiter 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'}

Une autre approche similaire (par @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
J'ai collé mon nez dans ton post. Espérons que cela ne vous dérange pas. Veuillez le modifier à votre guise.
piRSquared

Ah au contraire :) approche Nice, et le contrôle sur les grands dataframes il améliore légèrement les performances @piRSquared
YATU

12

Une façon 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'}

J'ai pensé ajouter une autre solution intelligente pour voir que c'était la même que la vôtre (-: whoops.
piRSquared

8

compréhension de dictionnaire

Utilisez l'une tupledes valeurs de colonne comme clé de hachage dans un dictionnaire

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

Juste au cas où nous n'aurions pas une représentation parfaite, je n'ai produit le dictionnaire que pour les colonnes où il y a une correspondance.

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

Cela frise l'absurde ... Ne faites pas ça.

{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
Comment se fait-il que je puisse comprendre chaque expression dans ces déclarations, sans voir pleinement dans ma tête ce qui se passe vraiment ici? Un peu comme les échecs, je sais comment déplacer toutes les pièces du plateau, mais je ne peux pas voir plus de 2 avancer.
Scott Boston

D'accord ... J'ai digéré cela maintenant et c'est encore tout simplement génial. +1
Scott Boston
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.