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.