ti-enxame.com

Python Pandas groupby aplicar argumentos lambda

Em um vídeo coursera sobre Python Pandas groupby (na introdução à ciência de dados em Python))), o exemplo a seguir dado:

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

Onde df é um DataFrame e o lambda é aplicado para calcular a soma de duas colunas. Se bem entendi, o objeto groupby (retornado por groupby) ao qual a função de aplicação é chamada é uma série de tuplas que consistem no índice que foi agrupado e na parte do DataFrame que é esse agrupamento específico.

O que eu não entendo é a maneira como o lambda é usado:

Existem três argumentos especificados (lambda df, a, b), mas apenas dois são explicitamente passados ​​('Weight (oz.)' E 'Quantity'). Como o intérprete sabe que os argumentos 'a' e 'b' são os especificados como argumentos e df é usado 'como está'?

Analisei os documentos, mas não consegui encontrar uma resposta definitiva para um exemplo tão específico. Eu estou pensando que isso tem a ver com df estar no escopo, mas não consigo encontrar informações para apoiar e detalhar esse pensamento.

7
g_uint

O próprio método apply passa cada "grupo" do objeto groupby como o primeiro argumento para a função. Portanto, ele sabe associar 'Peso' e "Quantidade" a a e b com base na posição. (por exemplo, eles são o segundo e o terceiro argumentos, se você contar o primeiro argumento do "grupo".

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

argumento implícito é cada "grupo" ou, neste caso, cada categoria

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

O "grp" é o primeiro argumento para o aviso da função lambda. Não preciso especificar nada para ele, pois já é automaticamente considerado como cada grupo do objeto groupby

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

Portanto, o Apply passa por cada um deles e executa uma operação de soma

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

Observe como isso é o mesmo que a primeira linha da nossa operação anterior

Portanto, aplicar é implicitamente passando cada grupo ao argumento da função como o primeiro argumento.

Do docs

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

args, kwargs: tupla e ditado

Argumentos posicionais e de palavras-chave opcionais para passar para func

Args adicionais passadas em "* args" são passadas após o argumento implícito do grupo.

então usando seu código

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

category
a     56
b    167
c     20
dtype: int64

aqui 'num1' e 'num2' estão sendo passados ​​como argumentos adicionais para cada chamada da função lambda

Portanto, o apply passa por cada um deles e executa sua operação 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
7
RSHAP