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.
3 Réponses :
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
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
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.
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.
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