Python - функции качения для объекта GroupBy

23

У меня есть объект временного ряда 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
    
задан ezbentley 21.12.2012 в 20:49
источник
  • Как именно вы ожидаете, что функция качения будет работать над сгруппированными объектами (я имею в виду выписать математику, которую вы хотите сделать в символах)? –  tacaswell 21.12.2012 в 21:06
  • Извините, я должен был быть более ясным. –  ezbentley 21.12.2012 в 21:28
  • Итак, вы хотите сделать cumsum на каждой из групп, а затем сшить все это в один кадр данных? –  tacaswell 21.12.2012 в 21:34
  • Да, идеально cumsum и любая функция катания (средняя, ​​сумма, std). –  ezbentley 21.12.2012 в 21:43

3 ответа

27
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
    
ответ дан Garrett 22.12.2012 в 00:41
  • pd.rolling_mean теперь устарел для Series и будет удален, используйте df.groupby ('id') ['x']. roll (2) .mean () вместо этого –  kekert 12.10.2016 в 17:39
28

Для гуглеров, которые приходят на этот старый вопрос:

Относительно комментария @ kekert к ответу @ Гаррета, чтобы использовать новый

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)
    
ответ дан Kevin Wang 16.12.2016 в 20:31
  • Я думаю, вы можете использовать .transform, а не reset_index? –  TMrtSmith 17.11.2017 в 16:16
  • Это действительно не удается, если вы группируете несколько столбцов. Удаление первого аргумента (уровней) решает это, хотя по умолчанию удаляет все уровни. Таким образом, линия становится df ['x'] = df.groupby ('id') ['x']. Roll (2) .mean (). Reset_index (drop = True) –  Kartik Sreenivasan 22.01.2018 в 09:21
1

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

Я тестировал его с cumprod , cummax и cummin , и все они вернули ndarray. Я думаю, что панды достаточно умны, чтобы знать, что эти функции возвращают серию, и поэтому функция применяется как преобразование, а не агрегация.

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
    
ответ дан Zelazny7 22.12.2012 в 00:07