Окно Pandas с Groupby не работает должным образом

У меня есть кадр данных pandas, для которого я пытаюсь вычислить расширяющуюся оконную агрегацию после группировки по столбцам. Структура данных примерно такая:

df = pd.DataFrame([['A',1,2015,4],['A',1,2016,5],['A',1,2017,6],['B',1,2015,10],['B',1,2016,11],['B',1,2017,12],
               ['A',1,2015,24],['A',1,2016,25],['A',1,2017,26],['B',1,2015,30],['B',1,2016,31],['B',1,2017,32],
              ['A',2,2015,4],['A',2,2016,5],['A',2,2017,6],['B',2,2015,10],['B',2,2016,11],['B',2,2017,12]],columns=['Typ','ID','Year','dat'])\
.sort_values(by=['Typ','ID','Year'])

i.e.

    Typ ID  Year    dat
0   A   1   2015    4
6   A   1   2015    24
1   A   1   2016    5
7   A   1   2016    25
2   A   1   2017    6
8   A   1   2017    26
12  A   2   2015    4
13  A   2   2016    5
14  A   2   2017    6
3   B   1   2015    10
9   B   1   2015    30
4   B   1   2016    11
10  B   1   2016    31
5   B   1   2017    12
11  B   1   2017    32
15  B   2   2015    10
16  B   2   2016    11
17  B   2   2017    12

Мне нужно сгруппировать этот кадр данных по столбцам Type и ID, а затем вычислить расширяющееся среднее всех наблюдений по Year. Код, который я написал,

df.groupby(by=['Typ','ID','Year']).expanding().mean().reset_index()

из которого я ожидаю таких результатов вывода (игнорируя level_3):

    Typ ID  Year    level_3 dat
0   A   1   2015    6   14.0
1   A   1   2016    7   14.5
2   A   1   2017    8   15.0
3   A   2   2015    12  4.0
4   A   2   2016    13  4.5
5   A   2   2017    14  5.0
6   B   1   2015    9   20.0
7   B   1   2016    10  20.5
8   B   1   2017    11  21.0
9   B   2   2015    15  10.0
10  B   2   2016    16  10.5
11  B   2   2017    17  11.0

Группировка по ['Type','ID','Year'] должна привести к одной строке для каждой уникальной строки этих столбцов. Вместо этого код дает следующее:

Typ ID  Year    level_3 dat
0   A   1   2015    0   4.0
1   A   1   2015    6   14.0
2   A   1   2016    1   5.0
3   A   1   2016    7   15.0
4   A   1   2017    2   6.0
5   A   1   2017    8   16.0
6   A   2   2015    12  4.0
7   A   2   2016    13  5.0
8   A   2   2017    14  6.0
9   B   1   2015    3   10.0
10  B   1   2015    9   20.0
11  B   1   2016    4   11.0
12  B   1   2016    10  21.0
13  B   1   2017    5   12.0
14  B   1   2017    11  22.0
15  B   2   2015    15  10.0
16  B   2   2016    16  11.0
17  B   2   2017    17  12.0

Похоже, что оконная функция expanding() работает с groupby неправильно, или, по крайней мере, она ведет себя не так, как я ожидаю, учитывая логику. Что я делаю не так?

Изменить: теперь я вижу, что я делаю неправильно, поскольку я ожидал другой интеграции между groupby и expanding. Итак, теперь мой вопрос заключается в том, как я могу использовать pandas для получения желаемого результата - без какой-либо ручной итерации.


person Dr. Andrew    schedule 12.08.2019    source источник
comment
он не работает, вероятно, потому что ему нужно определенное «окно» для выполнения sum. по умолчанию окно равно 1, поэтому оно увеличивает окно по одному и добавляет. если вы измените окно на 2, вы получите сумму 2 строк, но группы только с 1 значением и первым значением в каждой группе будут иметь значение «NaN»   -  person moys    schedule 12.08.2019
comment
Хм, но тогда это несовместимо с groupby...   -  person Dr. Andrew    schedule 12.08.2019
comment
Позволю себе не согласиться. Если вы 'groupby' просто наберете & &, а затем выполните расширение om 'DAT', вы увидите, что сумма суммируется (если вы измените окно, вы увидите разницу).   -  person moys    schedule 12.08.2019
comment
Ну, может быть, я действительно что-то упускаю, но, как я вижу, df.groupby(by=['Typ','ID','Year']) в начале должен вызывать результат 1 строки для каждого уникального Typ+ID+Year...   -  person Dr. Andrew    schedule 13.08.2019
comment
окно для расчета sum() равно 1, а не количеству результатов. Следующее приращение равно 2 (1 + 1), поэтому оно дает сумму 2 строк. если окно равно 2, оно будет вычислять sum() минимум 2 строк, затем 4 (2+2), затем 6 (2+2+2) и так далее.   -  person moys    schedule 13.08.2019
comment
Спасибо, я вижу и понимаю лучше. Я отредактировал вопрос.   -  person Dr. Andrew    schedule 14.08.2019
comment
Добавил ответ, пожалуйста, проверьте :)   -  person Ankur Sinha    schedule 14.08.2019


Ответы (1)


Расширение среднего, насколько мне известно, имеет другой способ расчета. Для желаемого результата я бы сделал следующее, используя комбинацию groupby и cumsum, а затем простое деление между sum и count:

newDf = df.groupby(['Typ','ID','Year'])['dat'].agg(('sum', 'count')).groupby(['Typ','ID']).cumsum()
newDf['dat'] = newDf['sum']/newDf['count']
newDf = newDf.reset_index().drop(['count', 'sum'], axis = 1)

Выход:

   Typ  ID  Year   dat
0    A   1  2015  14.0
1    A   1  2016  14.5
2    A   1  2017  15.0
3    A   2  2015   4.0
4    A   2  2016   4.5
5    A   2  2017   5.0
6    B   1  2015  20.0
7    B   1  2016  20.5
8    B   1  2017  21.0
9    B   2  2015  10.0
10   B   2  2016  10.5
11   B   2  2017  11.0
person Ankur Sinha    schedule 14.08.2019
comment
Это хорошее использование cumsum. Я не уверен, должен ли я сделать это как совершенно отдельный вопрос, но я должен уточнить, что мне нужно решение, которое будет работать для других показателей, в частности для медианы и стандартного значения. - person Dr. Andrew; 14.08.2019
comment
Возможно, вы могли бы выделить его в отдельный вопрос, если есть универсальное решение, потому что это, я полагаю, отвечает только на ваш текущий вопрос. Я не удивлюсь, если вам придется написать свою пользовательскую функцию. Однако, поскольку вы попросили решение для панд, я мог просто подумать об этом. Тем не менее, рад узнать, что вы нашли его хорошим пользователем cumsum :) - person Ankur Sinha; 14.08.2019