2
votes

mettre à jour / fusionner et mettre à jour un sous-ensemble de colonnes pandas

J'ai df1:

    ID1      ID2    ColA    ColB    ColC
0   45.0    23.0    a       1.0     xyz
1   56.0    24.0    b       2.0     abc
2   23.0    45.0    NaN     0.0     e
3   56.0    29.0    NaN     0.0     NaN

df2:

u = df1.set_index(['ID1','ID2'])
u = u.loc[u.index.dropna()]
v = df2.set_index(['ID1','ID2'])
v= v.loc[v.index.dropna()]
v.update(u)
v.reset_index()

I J'essaie de mettre à jour df2 uniquement sur les colonnes qui seront un choix = ['ColA', 'ColB'] ID1 et ID2 correspondent dans les 2 dfs.

Résultat attendu:

  ColA   ColB   ID1  ColC    ID2
0    a    1.0  45.0   NaN   23.0
1    b    2.0  56.0   NaN   24.0
2  NaN      0   NaN    fd   25.0
3  NaN      0   NaN   NaN   26.0
4  NaN      0   23.0    e   45.0
5  NaN      0   45.0    r    NaN
6  NaN      0   56.0  NaN   29.0

Jusqu'à présent, j'ai essayé:

  ColA  ColB   ID1 ColC   ID2
0    i     0  45.0  NaN  23.0
1    j     0  56.0  NaN  24.0
2  NaN     0   NaN   fd  25.0
3  NaN     0   NaN  NaN  26.0
4  NaN     0  23.0    e  45.0
5  NaN     0  45.0    r   NaN
6  NaN     0  56.0  NaN  29.0

Ce qui me donne la bonne mise à jour (mais je perds les Ids qui sont NaN) aussi la mise à jour a lieu sur ColC dont je ne veux pas:

  ColA  ColB   ID1    ColC   ID2
0    a   1.0  45.0     xyz  23.0
1    b   2.0  56.0     abc  24.0
2    c   3.0  34.0  qwerty  28.0
3    d   4.0  34.0     wer  33.0
4    e   NaN   NaN     NaN   NaN

J'ai également essayé merge et combine_first. impossible de comprendre quelle est la meilleure approche pour le faire en fonction de la liste de choix.


0 commentaires

3 Réponses :


2
votes

voici un moyen

df1

  ColA  ColB   ID1 ColC   ID2
0    a   1.0  45.0  NaN  23.0
1    b   2.0  56.0  NaN  24.0
2  NaN   0.0   NaN   fd  25.0
3  NaN   0.0   NaN  NaN  26.0
4  NaN   0.0  23.0    e  45.0
5  NaN   0.0  45.0    r   NaN
6  NaN   0.0  56.0  NaN  29.0

df2

  ColA  ColB   ID1 ColC   ID2
0    i     0  45.0  NaN  23.0
1    j     0  56.0  NaN  24.0
2  NaN     0   NaN   fd  25.0
3  NaN     0   NaN  NaN  26.0
4  NaN     0  23.0    e  45.0
5  NaN     0  45.0    r   NaN
6  NaN     0  56.0  NaN  29.0


df3 = df1.merge(df2, on=['ID1','ID2'], left_index=True)[['ColA_x','ColB_x']]
df2.loc[df3.index, 'ColA'] = df3['ColA_x']
df2.loc[df3.index, 'ColB'] = df3['ColB_x']

sortie

  ColA  ColB   ID1    ColC   ID2
0    a   1.0  45.0     xyz  23.0
1    b   2.0  56.0     abc  24.0
2    c   3.0  34.0  qwerty  28.0
3    d   4.0  34.0     wer  33.0
4    e   NaN   NaN     NaN   NaN


1 commentaires

Merci, je vérifierai dans un moment et vous le ferai savoir. Bdw, le problème est que j'ai beaucoup de telles colonnes et pas seulement 2 comme dans l'exemple. :)



1
votes

Il semble y avoir encore le problème dans 0.24 NaN fusionne avec NaN quand ce sont des clés. Évitez cela en supprimant ces enregistrements avant la fusion. Je suppose que ['ID1', 'ID2'] est une clé unique pour df1 (pour les lignes où les deux ne sont pas nulles):

#df3 =  df3.sort_index(axis=1)  # If not sorted _x left of _y
df3.groupby([x[0] for x in df3.columns.str.split('_')], axis=1).apply(lambda x: x.ffill(1).iloc[:, -1])

  ColA  ColB ColC   ID1   ID2
0    a   1.0  NaN  45.0  23.0
1    b   2.0  NaN  56.0  24.0
2  NaN   0.0   fd   NaN  25.0
3  NaN   0.0  NaN   NaN  26.0
4  NaN   0.0    e  23.0  45.0
5  NaN   0.0    r  45.0   NaN
6  NaN   0.0  NaN  56.0  29.0


3 commentaires

j'ai donc essayé cette logique, en utilisant df3 = df2.merge (df1 [mises à jour + clés] .dropna (sous-ensemble = clés), on = keys, how = 'left', suffixes = ('', '_ y') ) et df3.groupby (df3.columns.str.strip ('_ y'). tolist (), axis = 1) .apply (lambda x: x.ffill (1) .iloc [: , -1]) puisque j'avais des traits de soulignement dans les noms de colonnes comme Col_A , Col_B , ne fonctionnait pas. :(


@ anky_91. Dans ce cas, vous pouvez ajouter des suffixes "plus rares" (moins susceptibles de correspondre à une chaîne aléatoire dans vos colonnes) à la fusion, essayez d'ajouter suffixes = ['_ lmerge', '_rmerge'] puis < code> .groupby (df3.columns.str.replace ('_ lmerge | _rmerge', ''), axis = 1) avec la même logique. Bien qu'il semble que vous ayez déjà trouvé votre réponse.


J'essaierais de le faire à nouveau et en fonction des performances, je pourrais sélectionner le meilleur. :) merci beaucoup d'avoir lu votre temps pour ma question. :) Oui, la réponse de jez fonctionne plutôt bien dans les vrais dfs.



2
votes

Utilisez merge avec right join puis combine_first :

choice= ['ColA','ColB']
joined = ['ID1','ID2']
c = choice + joined

df3 = df1[c].merge(df2[c], on=joined, suffixes=('','_'), how='right')[c]
print (df3)
  ColA  ColB   ID1   ID2
0    a   1.0  45.0  23.0
1    b   2.0  56.0  24.0
2  NaN   NaN   NaN  25.0
3  NaN   NaN   NaN  26.0
4  NaN   NaN  23.0  45.0
5  NaN   NaN  45.0   NaN
6  NaN   NaN  56.0  29.0

df2[c] = df3.combine_first(df2[c])
print (df2)
  ColA  ColB   ID1 ColC   ID2
0    a   1.0  45.0  NaN  23.0
1    b   2.0  56.0  NaN  24.0
2  NaN   0.0   NaN   fd  25.0
3  NaN   0.0   NaN  NaN  26.0
4  NaN   0.0  23.0    e  45.0
5  NaN   0.0  45.0    r   NaN
6  NaN   0.0  56.0  NaN  29.0


2 commentaires

1 question, les noms d'identifiant dans mon dataframe d'origine sont différents, auraient besoin de left_on et right on, dans ce cas, devrais-je inclure toutes les clés dans c?


@ anky_91 - Je pense que pour un code plus simple, il est préférable de renommer les colonnes pour les mêmes dans les deux dataframes. Parce que left_on et right_on colonnes dupliquées - mêmes valeurs que des noms de colonnes différents.