Метод Pandas GroupBy.apply дублирует первую группу

Мой первый вопрос SO: Я смущен этим поведением метода groupby в pandas (0.12.0-4), он, как представляется, применяет функцию TWICE к первой строке кадра данных. Например:

>>> from pandas import Series, DataFrame
>>> import pandas as pd
>>> df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count':[1,0,2]})
>>> print(df)
   class  count  
0     A      1  
1     B      0    
2     C      2

Сначала я проверю, что функция groupby работает нормально, и кажется, что это нормально:

>>> for group in df.groupby('class', group_keys = True):
>>>     print(group)
('A',   class  count
0     A      1)
('B',   class  count
1     B      0)
('C',   class  count
2     C      2)

Затем я пытаюсь сделать что-то подобное, используя apply на объекте groupby, и я получаю первый вывод строки дважды:

>>> def checkit(group):
>>>     print(group)
>>> df.groupby('class', group_keys = True).apply(checkit)
  class  count
0     A      1
  class  count
0     A      1
  class  count
1     B      0
  class  count
2     C      2

Любая помощь будет оценена! Спасибо.

Изменить: @Jeff предоставляет ответ ниже. Я плотный и не сразу понял, так что вот простой пример, чтобы показать, что, несмотря на двойную распечатку первой группы в приведенном выше примере, метод apply работает только один раз в первой группе и не мутирует исходный кадр данных

>>> def addone(group):
>>>     group['count'] += 1
>>>     return group

>>> df.groupby('class', group_keys = True).apply(addone)
>>> print(df)

      class  count
0     A      1
1     B      0
2     C      2

Но, назначив возврат метода новому объекту, мы видим, что он работает так, как ожидалось:

  

df2 = df.groupby('class', group_keys = True).apply(addone)     печать (df2)

  
      class  count
0     A      2
1     B      1
2     C      3

Ответ 1

Это по дизайну, как описано здесь и здесь

Функция apply должна знать форму возвращаемых данных, чтобы разумно определить, как она будет объединена. Для этого он вызывает функцию (checkit в вашем случае) дважды, чтобы добиться этого.

В зависимости от вашего фактического варианта использования вы можете заменить вызов apply на aggregate, transform или filter, как описано подробно здесь. Эти функции требуют, чтобы возвращаемое значение было определенной формой, поэтому не вызывайте эту функцию дважды.

Однако, если функция, которую вы вызываете, не имеет побочных эффектов, скорее всего, не имеет значения, что функция вызывается дважды по первому значению.

Ответ 2

Эта "проблема" теперь исправлена: обновите до 0. 25+

Начиная с v0.25, GroupBy.apply() будет оценивать первую группу только один раз. Смотри GH24748.

Соответствующий пример из документации:

pd.__version__                                                                                                          
# '0.25.0.dev0+590.g44d5498d8'

df = pd.DataFrame({"a": ["x", "y"], "b": [1, 2]})                                                                      

def func(group): 
    print(group.name) 
    return group                                                                                                                     

Новое поведение (> = v0.25):

df.groupby('a').apply(func)                                                                                            
x
y

   a  b
0  x  1
1  y  2

Старое поведение (<= v0.24.x):

df.groupby('a').apply(func)
x
x
y

   a  b
0  x  1
1  y  2

Pandas по-прежнему использует первую группу, чтобы определить, может ли apply быстрый путь или нет. Но, по крайней мере, больше не нужно оценивать первую группу дважды. Хорошая работа, разработчики!

Ответ 3

Вы можете использовать для цикла, чтобы избежать дублирования groupby.apply первой строки,

log_sample.csv

guestid,keyword
1,null
2,null
2,null
3,null
3,null
3,null
4,null
4,null
4,null
4,null

мой фрагмент кода

df=pd.read_csv("log_sample.csv") 
grouped = df.groupby("guestid")

for guestid, df_group in grouped:
    print(list(df_group['guestid'])) 

df.head(100)

выход

[1]
[2, 2]
[3, 3, 3]
[4, 4, 4, 4]