web-dev-qa-db-ja.com

Python-GroupByオブジェクトのローリング関数

タイプ_<pandas.core.groupby.SeriesGroupBy object at 0x03F1A9F0>_の時系列オブジェクトgroupedがあります。 grouped.sum()は望ましい結果を与えますが、rolling_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
_
34
user1642513

注: @kekertで識別されるように、次のpandasパターンは廃止されました。以下の回答の現在のソリューションを参照してください。

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
35
Garrett

この古い質問に出くわしたGoogle社員向け:

新しいガレットの回答に対する@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インデックスで特異的にインデックス付けされたシリーズを返すだけで、おそらくあまり意味がありませんが、そのシリーズを元のデータフレームに新しい列として追加するのに非常に便利です。

だから、新しいrolling()メソッドを使用しても同じように動作する解決策を見つけたと思います:

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)
68
Kevin Wang

これは、パンダの expanding メソッドをうまく一般化する別の方法です。

これは非常に効率的で、時系列などの固定ウィンドウで ローリングウィンドウの計算 に対しても完全に機能します。

# 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
Sean McCarthy

メカニズムはわかりませんが、これは機能します。返される値はndarrayにすぎないことに注意してください。この方法で累積または「ローリング」関数を適用でき、同じ結果になるはずです。

cumprodcummax、および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
2
Zelazny7