2
votes

Fusion de dataframes en fonction d'une valeur de colonne

J'ai 2 grandes trames de données, en dessous de 2 ne sont que des exemples de ce à quoi ces 2 ressembleraient.

node  st1  st2
 a     8   -1
 b     4    6
 c     3    4

Je souhaite mettre à jour les valeurs de colonne df1, st1 et st2 avec les valeurs de colonne df2, st1 et st2, uniquement si les noms de nœuds des deux blocs de données correspondent. ÉGALEMENT, si les valeurs des colonnes st1 ou st2 dans df1 sont égales à -1, ne mettez pas à jour pour cette ligne et cette colonne, c'est-à-dire conservez-les à -1. Le résultat ressemblerait à quelque chose comme,

df1 = pd.DataFrame(columns=['node', 'st1', 'st2'], data=[['a', 1, -1], ['b', 2, 2], ['c', 3, 4]])

node  st1  st2 
 a    1   -1
 b    2    2
 c    3    4

df2 = pd.DataFrame(columns=['node', 'st1', 'st2'], data=[['a', 8, 5], ['b', 4, 6]])

node  st1  st2
 a    8    5
 b    4    6

J'ai essayé de fusionner les 2 blocs de données en utilisant la fusion de pandas de base avec jointure gauche, ce qui me donnerait un df avec des colonnes en double, puis boucle sur chaque ligne dans le df résultant pour vérifier les valeurs de st1 et st2, et les remplacer uniquement si ce n'est pas -1. Mais cela prendrait beaucoup de temps dans des cadres de données plus volumineux, c'est pourquoi j'aimerais trouver le moyen le plus efficace de le faire.


0 commentaires

3 Réponses :


3
votes

Vous pouvez définir node comme index dans les deux dataframes, définir sur NaN toutes les valeurs sauf -1s et utiliser DataFrame.combine_first à remplir NaNs dans df1 avec les valeurs dans df2 avec index partagé:

df = df1.set_index('node')
df.where(df.eq(-1)).combine_first(df2.set_index('node')).fillna(df)

      st1  st2
node          
a     8.0 -1.0
b     4.0  6.0
c     3.0  4.0


2 commentaires

Cela se transforme inutilement en flottant


Oui, car il se convertit en Nan à un moment donné. Qui est traité comme un flotteur. Peut facilement être converti en int



1
votes

Une façon est d'indexer où -1 apparaît, puis de fusionner toutes les données dans df1 à partir de df2 . Remplacez ensuite vos valeurs -1 (ici, je remplace en fait les valeurs non -1 par les nouvelles valeurs). Vous devrez définir l'index en tant que nœud pour que cela fonctionne:

df1 = df1.set_index('node')
df2 = df2.set_index('node')

no_repl = df1 == -1
new_df = df2.combine_first(df1)
new_df = df1.where(no_repl, new_df).reset_index()

Même idée que le message de @ yatu. Syntaxe légèrement différente.


2 commentaires

Cela ne fusionne pas sur node . combine_first utilisera les index pour ce faire, mais pour ce nœud doit être défini sur index


Bonne prise. Oui, j'ai oublié de définir l'index. En fait, en regardant votre réponse, c'est à peu près la même idée +1.



0
votes
df3 = df1.set_index('node')
df4 = df2.set_index('node')
keep_loc = (df3 == -1) | ~df3.index.isin(df4.index)[:, np.newaxis]
df3.where(keep_loc, df4)

      st1  st2
node          
a       8   -1
b       4    6
c       3    4

0 commentaires