Как сгруппировать, суммировать и вычислить среднее значение каждого другого элемента в столбце?

#python #pandas

Вопрос:

В моем фрейме данных у меня есть несколько имен (строка), дат (datetime64) и количество наблюдений (число).

 In [8]: df 
Out[8]: 
   name date  num
0     a    1    3
1     a    2    4
2     a    3    9
3     b    1    6
4     b    2    8
5     b    3    3

 

Что я хочу, так это рассчитать для каждого имени среднее актуальное значение. Поэтому я ожидаю, что для каждого имени будет следующий дополнительный столбец:

    
   name date  num   avg
0     a    1    3     3
1     a    2    4   3.5
2     a    3    9  5.33
3     b    1    6     6
4     b    2    8     7
5     b    3    3  5.67
 

3 = 3/1; 3.5 = (3 4)/2; 5.33 = (3 4 9)/3 и так далее для любого другого имени.

Я пытался объединить функции панд groupby avg и cumsum, но не могу получить то, что я хочу.

Есть некоторые требования: мне нужно использовать функции pandas (без циклов) и в лучшем случае избегать использования лямбд, так как мой df большой.

Комментарии:

1. Ваши входные и ожидаемые выходные фреймы данных не совпадают. число индекса 5 изменилось с 3 до 9.

Ответ №1:

Использовать groupby с expanding и mean :

 df['avg'] = df.groupby('name')['num'].expanding().mean().reset_index(level=0, drop=True)
 

Выход:

   name  date  num       avg
0    a     1    3  3.000000
1    a     2    4  3.500000
2    a     3    9  5.333333
3    b     1    6  6.000000
4    b     2    8  7.000000
5    b     3    3  5.666667
 

Комментарии:

1. В столбце дата у меня есть несколько дат в будущем, и именно поэтому соответствующие значения num-это NaN. Если мы возьмем имя «а», например, я получу для дат 4, 5, 6 трижды 5.333333, 5.333333, 5.333333. Но вместо этого я хочу Нан. Как я могу это сделать?

2. @Android44 Вы добавляете такую маску df.groupby('name')['num'].expanding().mean(skipna=True).reset_index(level=0, drop=True).mask(df['num'].isna())

Ответ №2:

Вы можете разделить совокупную сумму на совокупное количество (добавлено 1) для каждой группы:

 g = df.groupby("name").num
df["avg"] = g.cumsum() / g.cumcount().add(1)
 

add(1) где мы будем считать, так как это так, но нам нужно 0, 1, 2.. 1, 2, 3.. ,

получить

 >>> df

  name  date  num       avg
0    a     1    3  3.000000
1    a     2    4  3.500000
2    a     3    9  5.333333
3    b     1    6  6.000000
4    b     2    8  7.000000
5    b     3    3  5.666667
 

Комментарии:

1. Что «num» предполагает делать? Я получаю сообщение об ошибке

2. @Android44, который выбирает num столбец после groupby (альтернативный синтаксис ["num"] ). У тебя есть колонка с названием num , верно? Не могли бы вы поделиться ошибкой, пожалуйста?

3. Вы правы, в исходном наборе данных у меня есть другое имя столбца.