Groupby()。Sum()を使用して新しい列を作成するにはどうすればよいですか?
2つの方法があります。1つは簡単で、もう1つはもう少し興味深い方法です。
みんなのお気に入り:GroupBy.transform()
付き'sum'
@Ed Chumの答えは、少し単純化できます。DataFrame.groupby
ではなく呼び出しSeries.groupby
ます。これにより、構文が単純になります。
df[['Date', 'Data3']]
Date Data3
0 2015-05-08 5
1 2015-05-07 8
2 2015-05-06 6
3 2015-05-05 1
4 2015-05-08 50
5 2015-05-07 100
6 2015-05-06 60
7 2015-05-05 120
df.groupby('Date')['Data3'].transform('sum')
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Data3, dtype: int64
少し速いです、
df2 = pd.concat([df] * 12345)
%timeit df2['Data3'].groupby(df['Date']).transform('sum')
%timeit df2.groupby('Date')['Data3'].transform('sum')
10.4 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
8.58 ms ± 559 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
型にはまらないが、検討する価値がある:GroupBy.sum()
+Series.map()
私はAPIの興味深い特異性に出くわしました。私の言うことから、これは0.20を超えるメジャーバージョンで再現できます(0.23と0.24でテストしました)。のtransform
直接関数を使用し、次を使用してGroupBy
ブロードキャストすると、所要時間の数ミリ秒を一貫して短縮できるようですmap
。
df.Date.map(df.groupby('Date')['Data3'].sum())
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Date, dtype: int64
と比べて
df.groupby('Date')['Data3'].transform('sum')
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Data3, dtype: int64
私のテストでは、それが表示されmap
ますが、直接使用する余裕があれば少し速くなるGroupBy
(のような機能をmean
、min
、max
、first
、など)。約20万レコードまでのほとんどの一般的な状況では、多かれ少なかれ高速です。その後、パフォーマンスは実際にはデータに依存します。
(左:v0.23、右:v0.24)
知っておくと便利な代替手段です。フレームが小さく、グループの数が少ない場合に適しています。。。しかし、私はtransform
最初の選択肢としてお勧めします。とにかくこれは共有する価値があると思いました。
参考のためのベンチマークコード:
import perfplot
perfplot.show(
setup=lambda n: pd.DataFrame({'A': np.random.choice(n//10, n), 'B': np.ones(n)}),
kernels=[
lambda df: df.groupby('A')['B'].transform('sum'),
lambda df: df.A.map(df.groupby('A')['B'].sum()),
],
labels=['GroupBy.transform', 'GroupBy.sum + map'],
n_range=[2**k for k in range(5, 20)],
xlabel='N',
logy=True,
logx=True
)