pandas groupby()。sum()の出力から新しい列を作成するにはどうすればよいですか?


84

groupby計算から新しい列を作成しようとしています。以下のコードでは、各日付の正しい計算値を取得しています(以下のグループを参照)が、それを使用して新しい列(df['Data4'])を作成しようとすると、NaNが取得されます。そのData3ため、すべての日付の合計を使用してデータフレームに新しい列を作成し、それを各日付行に適用しようとしています。たとえば、2015-05-08は2行にあり(合計は50 + 5 = 55)、この新しい列では、両方の行に55を入れたいと思います。

import pandas as pd
import numpy as np
from pandas import DataFrame

df = pd.DataFrame({
    'Date' : ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'], 
    'Sym'  : ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'], 
    'Data2': [11, 8, 10, 15, 110, 60, 100, 40],
    'Data3': [5, 8, 6, 1, 50, 100, 60, 120]
})

group = df['Data3'].groupby(df['Date']).sum()

df['Data4'] = group

回答:


192

transformこれを使用すると、インデックスがdfに揃えられたシリーズが返されるため、新しい列として追加できます。

In [74]:

df = pd.DataFrame({'Date': ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'], 'Sym': ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'], 'Data2': [11, 8, 10, 15, 110, 60, 100, 40],'Data3': [5, 8, 6, 1, 50, 100, 60, 120]})
​
df['Data4'] = df['Data3'].groupby(df['Date']).transform('sum')
df
Out[74]:
   Data2  Data3        Date   Sym  Data4
0     11      5  2015-05-08  aapl     55
1      8      8  2015-05-07  aapl    108
2     10      6  2015-05-06  aapl     66
3     15      1  2015-05-05  aapl    121
4    110     50  2015-05-08  aaww     55
5     60    100  2015-05-07  aaww    108
6    100     60  2015-05-06  aaww     66
7     40    120  2015-05-05  aaww    121

ここにあるような2番目のgroupbyがある場合はどうなりますか:stackoverflow.com/a/40067099/281545
Mr_and_Mrs_D 2018

@Mr_and_Mrs_Dインデックスをリセットし、その場合は共通の列で左マージを実行して、列を追加し
直す必要が

10
または、使用することもできますdf.groupby('Date')['Data3'].transform('sum')(覚えやすいと思います)。
クレブ2018

42

Groupby()。Sum()を使用して新しい列を作成するにはどうすればよいですか?

2つの方法があります。1つは簡単で、もう1つはもう少し興味深い方法です。


みんなのお気に入り:GroupBy.transform()付き'sum'

@Ed Chumの答えは、少し単純化できます。DataFrame.groupbyではなく呼び出しSeries.groupbyます。これにより、構文が単純になります。

# The setup.
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(のような機能をmeanminmaxfirst、など)。約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
)

1
これは知っておくと良いです!(少なくとも将来のperfplotsで)バージョン番号を含めていただけませんか?パフォーマンスの違いは興味深いものですが、結局のところ、これらは実装の詳細であり、将来的に解決される可能性があります。特に開発者があなたの投稿に注意を払う場合。
JPP

@jppうん、それは公平だ!バージョンを追加しました。これは0.23でテストされましたが、0.20を超えるバージョンがある限り、違いが見られると思います。
cs 9519
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.