J'essaie d'appliquer une fonction personnalisée dans les pandas similaire à la fonctionnalité groupby et mutate de dplyr.
Ce que j'essaie de faire, c'est de dire étant donné un cadre de données pandas comme celui-ci:
df = df.groupby(['category1', 'category2']).apply(myfunc_data)
appliquer une fonction qui renvoie le même nombre d'éléments que le nombre d'éléments dans le groupe en:
def myfunc_data(data): data['var3'] = myfunc(data.var1) return data
pour obtenir ce résultat p >
df <- df %>% group_by(category1, category2) %>% mutate( var3 = myfunc(var1) )
Je pensais à quelque chose comme:
df['var3'] = df.groupby(['category1', 'category2'], group_keys=False).apply(lambda x: myfunc(x.var1))
mais je n'ai pas réussi à faire correspondre l'index.
En R avec dplyr, ce serait
df category1 category2 var1 var2 var3 0 a a 23 59 35.5 1 a b 54 20 54 2 a a 48 62 35.5 3 b b 45 76 29 4 b a 60 26 60 5 b b 13 70 29
J'ai donc pu le résoudre en utilisant une fonction personnalisée comme:
def myfunc(s): return [np.mean(s)] * len(s)
et
df = pd.DataFrame({'category1':['a','a','a', 'b', 'b','b'], 'category2':['a', 'b', 'a', 'b', 'a', 'b'], 'var1':np.random.randint(0,100,6), 'var2':np.random.randint(0,100,6)} ) df category1 category2 var1 var2 0 a a 23 59 1 a b 54 20 2 a a 48 62 3 b b 45 76 4 b a 60 26 5 b b 13 70
mais je suppose que je me demandais toujours s'il existe un moyen de le faire sans définir cette fonction personnalisée.
p>
3 Réponses :
Essayez la solution suivante:
df.loc[:,'var3'] = df.groupby(['category1', 'category2']).var1.transform(myfunc)
Utilisez GroupBy.transform
pour le retour de Series
avec une taille sime telle que DataFrame
d'origine, donc possible attribuer à une nouvelle colonne:
df['var3'] = (df.groupby(['category1', 'category2'])['var1'] .transform(lambda s: [np.mean(s)] * len(s)))
Ah compris, juste en général, y a-t-il de bonnes ressources à comprendre comme essayer de faire une correspondance d'index, groupby, appliquer, etc.?
@jtanman - À propos de l'agrégation, il est possible de vérifier ceci .
Vous pouvez techniquement y parvenir en utilisant apply
, que je vais ajouter ici pour être complet, mais je recommanderais d'utiliser la méthode transform
- c'est plus simple et plus rapide.
Le problème que vous avez eu est que vous avez renvoyé plusieurs valeurs qui, lorsque vous utilisez apply
, vous donne une liste pour chaque ligne. Au lieu de cela, vous pouvez renvoyer une seule valeur et vous fier à pandas
pour faire correspondre ces valeurs (et les dupliquer si nécessaire) lorsque vous ajoutez dans la nouvelle colonne. Pour que cela fonctionne, cependant, nous devons avoir le même index que la série renvoyée par groupby / apply. Voici comment procéder (notez également la modification de myfunc
):
import pandas as pd def myfunc(s): return np.mean(s) df = pd.DataFrame({'category1':['a','a','a', 'b', 'b','b'], 'category2':['a', 'b', 'a', 'b', 'a', 'b'], 'var1':np.random.randint(0,100,6), 'var2':np.random.randint(0,100,6)} ) df = (df.set_index(["category1", "category2"]) .assign(var3=df.groupby(["category1", "category2"]).var1.apply(myfunc)) .reset_index() ) df
Ah merci! Oui, je savais que mon problème était lié aux index correspondants, car j'étais capable de générer la liste entière, sauf que ce serait une cellule au lieu de la faire correspondre aux données groupby sous forme de colonne.