multiple groupby funcion from examples example create columns and python pandas pandas-groupby

python - funcion - df.groupby(…).agg(conjunto) produce resultados diferentes en comparación con df.groupby(…).agg(lambda x: conjunto(x))



pandas groupby count (2)

OK, lo que está sucediendo aquí es que el set no se está manejando ya que no is_list_like en _aggregate :

elif is_list_like(arg) and arg not in compat.string_types:

ver source

esto no es is_list_like por lo que no devuelve None a la cadena de llamadas para terminar en esta línea:

results.append(colg.aggregate(a))

ver source

esto genera TypeError como TypeError: ''type'' object is not iterable

que luego plantea:

if not len(results): raise ValueError("no results")

ver source

_aggregate_generic no tenemos resultados, terminamos llamando a _aggregate_generic :

ver source

esto entonces llama:

result[name] = self._try_cast(func(data, *args, **kwargs)

ver source

Esto luego termina como:

(Pdb) n > c:/programdata/anaconda3/lib/site-packages/pandas/core/groupby.py(3779)_aggregate_generic() -> return self._wrap_generic_output(result, obj) (Pdb) result {1: {''user_id'', ''instructor'', ''class_type''}, 2: {''user_id'', ''instructor'', ''class_type''}, 3: {''user_id'', ''instructor'', ''class_type''}, 4: {''user_id'', ''instructor'', ''class_type''}}

Estoy ejecutando una versión ligeramente diferente de pandas pero la línea de origen equivalente es https://github.com/pandas-dev/pandas/blob/v0.22.0/pandas/core/groupby.py#L3779

Básicamente, debido a que set no cuenta como una función o iterable, simplemente colapsa para llamar al ctor en la iterable serie que en este caso son las columnas, puede ver el mismo efecto aquí:

In [8]: df.groupby(''user_id'').agg(lambda x: print(set(x.columns))) {''class_type'', ''instructor'', ''user_id''} {''class_type'', ''instructor'', ''user_id''} {''class_type'', ''instructor'', ''user_id''} {''class_type'', ''instructor'', ''user_id''} Out[8]: class_type instructor user_id 1 None None 2 None None 3 None None 4 None None

pero cuando usa la lambda que es una función anónima, esto funciona como se esperaba.

Respondiendo a esta pregunta resultó que df.groupby(...).agg(set) y df.groupby(...).agg(lambda x: set(x)) están produciendo resultados diferentes.

Datos:

df = pd.DataFrame({ ''user_id'': [1, 2, 3, 4, 1, 2, 3], ''class_type'': [''Krav Maga'', ''Yoga'', ''Ju-jitsu'', ''Krav Maga'', ''Ju-jitsu'',''Krav Maga'', ''Karate''], ''instructor'': [''Bob'', ''Alice'',''Bob'', ''Alice'',''Alice'', ''Alice'',''Bob'']})

Manifestación:

In [36]: df.groupby(''user_id'').agg(lambda x: set(x)) Out[36]: class_type instructor user_id 1 {Krav Maga, Ju-jitsu} {Alice, Bob} 2 {Yoga, Krav Maga} {Alice} 3 {Ju-jitsu, Karate} {Bob} 4 {Krav Maga} {Alice} In [37]: df.groupby(''user_id'').agg(set) Out[37]: class_type instructor user_id 1 {user_id, class_type, instructor} {user_id, class_type, instructor} 2 {user_id, class_type, instructor} {user_id, class_type, instructor} 3 {user_id, class_type, instructor} {user_id, class_type, instructor} 4 {user_id, class_type, instructor} {user_id, class_type, instructor}

Espero el mismo comportamiento aquí, ¿sabes lo que me estoy perdiendo?


Quizás como @Edchum comentó agg aplica las funciones incorporadas de python considerando el objeto groupby como un mini marco de datos, mientras que cuando se pasa una función definida, se aplica a cada columna. Un ejemplo para ilustrar esto es a través de la impresión.

df.groupby(''user_id'').agg(print,end=''/n/n'') class_type instructor user_id 0 Krav Maga Bob 1 4 Ju-jitsu Alice 1 class_type instructor user_id 1 Yoga Alice 2 5 Krav Maga Alice 2 class_type instructor user_id 2 Ju-jitsu Bob 3 6 Karate Bob 3 df.groupby(''user_id'').agg(lambda x : print(x,end=''/n/n'')) 0 Krav Maga 4 Ju-jitsu Name: class_type, dtype: object 1 Yoga 5 Krav Maga Name: class_type, dtype: object 2 Ju-jitsu 6 Karate Name: class_type, dtype: object 3 Krav Maga Name: class_type, dtype: object ...

Espero que esta sea la razón por la cual la aplicación del conjunto dio el resultado como el mencionado anteriormente.