Voici un exemple de mon df:
def f(row):
if condition:
row["a"] = 3
elif condition:
row["a"] = 4
elif condition:
row_duplicated = row.copy()
row_duplicated["a"] = 5 # I need also this row to be included in the df
return row
df.apply(f, axis=1)
Et je veux arriver à ceci:
pd.DataFrame([["1", "2"], ["1", "2"], ["3", "other_value"], ["3", "row_duplicated_with_edits_in_this_column"]],
columns=["a", "b"])
a b
0 1 2
1 1 2
2 3 other_value
3 3 row_duplicated_with_edits_in_this_column
La règle est d'utiliser la méthode apply, effectuez quelques vérifications (pour garder l'exemple simple, je n'inclus pas ces vérifications), mais sous certaines conditions, pour certaines lignes de la fonction apply, dupliquez la ligne, modifiez la ligne et insérez les deux lignes dans le df.
Donc quelque chose comme:
pd.DataFrame([["1", "2"], ["1", "2"], ["3", "other_value"]],
columns=["a", "b"])
a b
0 1 2
1 1 2
2 3 other_value
Je ne veux pas stocker les lignes dupliquées quelque part dans ma classe et les ajouter à la fin. Je veux le faire à la volée.
J'ai vu ceci pandas: applique une fonction à DataFrame qui peut renvoyer plusieurs lignes mais je ne sais pas si groupby peut m'aider ici.
Merci
3 Réponses :
Voici une façon d'utiliser df.iterrows dans une compréhension de liste. Vous devrez ajouter vos lignes à une boucle, puis concaténer.
def func(row):
if row['a'] == "3":
row2 = row.copy()
# make edits to row2
return pd.concat([row, row2], axis=1)
return row
pd.concat([func(row) for _, row in df.iterrows()], ignore_index=True, axis=1).T
a b
0 1 2
1 1 2
2 3 other_value
3 3 other_value
J'ai trouvé que dans mon cas, c'est mieux sans ignore_index = True car je plus tard lors de la fusion de 2 dfs.
merci, cela fonctionne, j'aurais préféré utiliser apply (), car j'utilise df.query (). apply (). combine_first () , mais toujours avec de petites modifications, votre solution fonctionne sans avoir à stocker le données n'importe où.
Je le vectoriserais, en le faisant catégorie par catégorie:
df[df_condition_1]["a"] = 3 df[df_condition_2]["a"] = 4 duplicates = df[df_condition_3] # somehow we store it ? duplicates["a"] = 5 #then df.join(duplicates, how='outer')
Cette solution répond-elle à vos besoins?
merci, ce serait plus rapide, mais oui, mes conditions sont nombreuses et à travers plusieurs fonctions, donc ce genre de solution rendra le code moins lisible.
Votre logique semble généralement vectorisable. Comme l'ordre des lignes dans votre sortie semble être important, vous pouvez incrémenter le RangeIndex par défaut de 0,5, puis utiliser sort_index .
def row_appends(x):
newrows = x.loc[x['a'].isin(['3', '4', '5'])].copy()
newrows.loc[x['a'] == '3', 'b'] = 10 # make conditional edit
newrows.loc[x['a'] == '4', 'b'] = 20 # make conditional edit
newrows.index = newrows.index + 0.5
return newrows
res = pd.concat([df, df.pipe(row_appends)])\
.sort_index().reset_index(drop=True)
print(res)
a b
0 1 2
1 1 2
2 3 other_value
3 3 10
p>