пеленгатор.groupby (...).agg (set) дает другой результат по сравнению с df.groupby (...).agg (лямбда x: набор(x))
ответ этот вопрос выяснилось, что df.groupby(...).agg(set)
и df.groupby(...).agg(lambda x: set(x))
производят разные результаты.
данные:
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']})
демо:
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}
Я ожидал бы такого же поведения здесь - знаете, чего мне не хватает?
2 ответов
хорошо, что здесь происходит, это set
не обрабатывается, как это не is_list_like
на _aggregate
:
elif is_list_like(arg) and arg not in compat.string_types:
посмотреть источник
это не is_list_like
Итак, он возвращается None
вверх по цепочке вызовов, чтобы закончить на этой линии:
results.append(colg.aggregate(a))
посмотреть источник
поднимает TypeError
as TypeError: 'type' object is not iterable
, который затем поднимает:
if not len(results):
raise ValueError("no results")
посмотреть источник
поэтому, поскольку у нас нет результатов, мы в конечном итоге вызываем _aggregate_generic
:
посмотреть источник
это затем вызывает:
result[name] = self._try_cast(func(data, *args, **kwargs)
посмотреть источник
это потом заканчивается так:
(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'}}
я запускаю немного другую версию pandas, но эквивалентная исходная строка https://github.com/pandas-dev/pandas/blob/v0.22.0/pandas/core/groupby.py#L3779
так по существу потому что set
не считается функцией или итерацией, он просто сворачивается для вызова ctor на серии iterable, которые в этом случае являются столбцами, вы можете увидеть тот же эффект здесь:
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
но когда вы используете lambda
это анонимная функция это работает, как ожидалось.
возможно, как прокомментировал @Edchum agg
применяет встроенные функции python, рассматривая объект groupby как мини-фрейм данных, тогда как при передаче определенной функции он применяет ее для каждого столбца. В качестве примера можно привести print.
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
...
надеюсь, что это причина, по которой применение набора дало результат, подобный упомянутому выше.