3
votes

Groupby Appliquer des pandas de fonction personnalisée

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>


0 commentaires

3 Réponses :


2
votes

Essayez la solution suivante:

df.loc[:,'var3'] = df.groupby(['category1', 'category2']).var1.transform(myfunc)


0 commentaires

3
votes

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)))


2 commentaires

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 .



1
votes

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


1 commentaires

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.