Python - функции качения для объекта GroupBy
У меня есть объект временного ряда grouped
типа <pandas.core.groupby.SeriesGroupBy object at 0x03F1A9F0>
. grouped.sum()
дает желаемый результат, но я не могу заставить rol_sum работать с объектом groupby
. Есть ли способ применить функции качения к объектам groupby
? Например:
x = range(0, 6)
id = ['a', 'a', 'a', 'b', 'b', 'b']
df = DataFrame(zip(id, x), columns = ['id', 'x'])
df.groupby('id').sum()
id x
a 3
b 12
Однако я хотел бы иметь что-то вроде:
id x
0 a 0
1 a 1
2 a 3
3 b 3
4 b 7
5 b 12
Ответы
Ответ 1
Примечание: как определено @kekert, следующий шаблон панд устарел. Смотрите текущие решения в ответах ниже.
In [16]: df.groupby('id')['x'].apply(pd.rolling_mean, 2, min_periods=1)
Out[16]:
0 0.0
1 0.5
2 1.5
3 3.0
4 3.5
5 4.5
In [17]: df.groupby('id')['x'].cumsum()
Out[17]:
0 0
1 1
2 3
3 3
4 7
5 12
Ответ 2
Для гуглеров, которые приходят на этот старый вопрос:
Относительно комментария @kekert на ответ @Garrett для использования нового
df.groupby('id')['x'].rolling(2).mean()
а не устаревший
df.groupby('id')['x'].apply(pd.rolling_mean, 2, min_periods=1)
Любопытно, что новый подход .rolling(). mean() возвращает многоиндексированную серию, сначала индексированную столбцом group_by, а затем индекс. Принимая во внимание, что старый подход просто вернул бы серию, индексированную исключительно исходным индексом df, что, возможно, имеет меньшее значение, но очень удобно для добавления этой серии в новый столбец в исходный фрейм.
Итак, я думаю, что я нашел решение, которое использует новый метод roll() и по-прежнему работает одинаково:
df.groupby('id')['x'].rolling(2).mean().reset_index(0,drop=True)
который должен дать вам серию
0 0.0
1 0.5
2 1.5
3 3.0
4 3.5
5 4.5
который вы можете добавить в качестве столбца:
df['x'] = df.groupby('id')['x'].rolling(2).mean().reset_index(0,drop=True)
Ответ 3
Вот еще один способ, который хорошо обобщает и использует метод расширения панд.
Это очень эффективно, а также отлично подходит для расчета скользящих окон с фиксированными окнами, например, для временных рядов.
# Import pandas library
import pandas as pd
# Prepare columns
x = range(0, 6)
id = ['a', 'a', 'a', 'b', 'b', 'b']
# Create dataframe from columns above
df = pd.DataFrame({'id':id, 'x':x})
# Calculate rolling sum with infinite window size (i.e. all rows in group) using "expanding"
df['rolling_sum'] = df.groupby('id')['x'].transform(lambda x: x.expanding().sum())
# Output as desired by original poster
print(df)
id x rolling_sum
0 a 0 0
1 a 1 1
2 a 2 3
3 b 3 3
4 b 4 7
5 b 5 12
Ответ 4
Я не уверен в механике, но это работает. Обратите внимание, что возвращаемое значение - это просто ndarray. Я думаю, вы могли бы применить любую кумулятивную или "скользящую" функцию таким образом, и она должна иметь тот же результат.
Я тестировал его с помощью cumprod
, cummax
и cummin
, и все они вернули ndarray. Я думаю, что pandas достаточно умен, чтобы знать, что эти функции возвращают серию, и поэтому функция применяется как преобразование, а не агрегация.
In [35]: df.groupby('id')['x'].cumsum()
Out[35]:
0 0
1 1
2 3
3 3
4 7
5 12
Изменить: мне было любопытно, что этот синтаксис возвращает строку:
In [54]: df.groupby('id')['x'].transform('cumsum')
Out[54]:
0 0
1 1
2 3
3 3
4 7
5 12
Name: x