web-dev-qa-db-fra.com

Python Pandas groupby appliquer des arguments lambda

Dans une vidéo de coursera sur Python Pandas groupby (dans l'introduction à la science des données dans Python), l'exemple suivant est donné:

df.groupby('Category').apply(lambda df,a,b: sum(df[a] * df[b]), 'Weight (oz.)', 'Quantity')

Où df est un DataFrame et le lambda est appliqué pour calculer la somme de deux colonnes. Si je comprends bien, l'objet groupby (renvoyé par groupby) auquel la fonction apply est appelée est une série de tuples comprenant l'index qui a été groupé par et la partie du DataFrame qui est ce regroupement spécifique.

Ce que je ne comprends pas, c'est la façon dont le lambda est utilisé:

Il y a trois arguments spécifiés (lambda df, a, b), mais seulement deux sont explicitement passés ('Weight (oz.)' Et 'Quantity'). Comment l'interprète sait-il que les arguments "a" et "b" sont ceux spécifiés comme arguments et que df est utilisé "tel quel"?

J'ai regardé la documentation mais je n'ai pas pu trouver de réponse définitive pour un exemple aussi précis. Je pense que cela doit faire quelque chose avec df étant dans la portée mais ne peux pas trouver d'informations pour soutenir et détailler cette pensée.

8
g_uint

La méthode apply passe elle-même chaque "groupe" de l'objet groupby comme premier argument à la fonction. Il sait donc associer "Poids" et "Quantité" à a et b en fonction de la position. (par exemple, ce sont les 2e et 3e arguments si vous comptez le premier argument "groupe".

df = pd.DataFrame(np.random.randint(0,11,(10,3)), columns = ['num1','num2','num3'])
df['category'] = ['a','a','a','b','b','b','b','c','c','c']
df = df[['category','num1','num2','num3']]
df

  category  num1  num2  num3
0        a     2     5     2
1        a     5     5     2
2        a     7     3     4
3        b    10     9     1
4        b     4     7     6
5        b     0     5     2
6        b     7     7     5
7        c     2     2     1
8        c     4     3     2
9        c     1     4     6

gb = df.groupby('category')

l'argument implicite est chaque "groupe" ou dans ce cas chaque catégorie

gb.apply(lambda grp: grp.sum()) 

Le "grp" est le premier argument de la fonction lambda. Je n'ai pas besoin de spécifier quoi que ce soit pour cela car il est déjà, pris automatiquement pour être chaque groupe de l'objet groupby

         category  num1  num2  num3
category                           
a             aaa    14    13     8
b            bbbb    21    28    14
c             ccc     7     9     9

Donc, appliquer passe par chacun d'eux et effectue une opération de somme

print(gb.groups)
{'a': Int64Index([0, 1, 2], dtype='int64'), 'b': Int64Index([3, 4, 5, 6], dtype='int64'), 'c': Int64Index([7, 8, 9], dtype='int64')}

print('1st GROUP:\n', df.loc[gb.groups['a']])
1st GROUP:
  category  num1  num2  num3
0        a     2     5     2
1        a     5     5     2
2        a     7     3     4    


print('SUM of 1st group:\n', df.loc[gb.groups['a']].sum())

SUM of 1st group:
category    aaa
num1         14
num2         13
num3          8
dtype: object

Remarquez comment cela est le même que la première ligne de notre opération précédente

Donc, appliquer implicitement passer chaque groupe à l'argument de fonction comme premier argument.

De la docs

GroupBy.apply (func, * args, ** kwargs)

args, kwargs: Tuple et dict

Arguments de position et de mot-clé facultatifs à passer à func

Les arguments supplémentaires passés dans "* args" sont passés après l'argument de groupe implicite.

donc en utilisant votre code

gb.apply(lambda df,a,b: sum(df[a] * df[b]), 'num1', 'num2')

category
a     56
b    167
c     20
dtype: int64

ici 'num1' et 'num2' sont passés comme arguments supplémentaires à chaque appel de la fonction lambda

Donc, appliquer passe par chacun d'eux et effectue votre opération lambda

# copy and paste your lambda function
fun = lambda df,a,b: sum(df[a] * df[b])

print(gb.groups)
{'a': Int64Index([0, 1, 2], dtype='int64'), 'b': Int64Index([3, 4, 5, 6], dtype='int64'), 'c': Int64Index([7, 8, 9], dtype='int64')}

print('1st GROUP:\n', df.loc[gb.groups['a']])

1st GROUP:
   category  num1  num2  num3
0        a     2     5     2
1        a     5     5     2
2        a     7     3     4

print('Output of 1st group for function "fun":\n', 
fun(df.loc[gb.groups['a']], 'num1','num2'))

Output of 1st group for function "fun":
56
8
RSHAP