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
transform
を使用したい場合、dfに揃えられたインデックスを持つSeriesが返されるため、新しい列として追加できます。
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
Groupby()。Sum()を使用して新しい列を作成するにはどうすればよいですか?
2つの方法があります-簡単な方法と、もう少し興味深い方法です。
GroupBy.transform()
with '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
、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
)