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

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?

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 fuente

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 fuente

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

que luego plantea:

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

ver fuente

_aggregate_generic no tenemos resultados, terminamos llamando a _aggregate_generic :

ver fuente

esto entonces llama:

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

ver fuente

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.

Quizás como @Edchum comentó agg aplica las funciones incorporadas de python considerando el objeto groupby como un mini dataframe, 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.