パンダのgroupbyとローリングウィンドウ

Aug 21 2020

グループ化機能を適用した後、特定の期間の1つのフィールドの合計を計算しようとしています。

私のデータセットは次のようになります。

Date          Company   Country    Sold
01.01.2020       A          BE       1
02.01.2020       A          BE       0
03.01.2020       A          BE       1
03.01.2020       A          BE       1
04.01.2020       A          BE       1
05.01.2020       B          DE       1
06.01.2020       B          DE       0

行ごとに新しい列を追加して、過去7日間の販売済みの合計を計算します(各グループ「会社、国」ごと、現在の日は含まれません)。

Date          Company   Country    Sold      LastWeek_Count
01.01.2020       A          BE       1           0
02.01.2020       A          BE       0           1
03.01.2020       A          BE       1           1
03.01.2020       A          BE       1           1
04.01.2020       A          BE       1           3
05.01.2020       B          DE       1           0
06.01.2020       B          DE       0           1

次のことを試しましたが、現在の日付も含まれており、同じ日付、つまり2020年1月3日に異なる値が表示されます。

df['LastWeek_Count'] = df.groupby(['Company', 'Country']).rolling(7, on ='Date')['Sold'].sum().reset_index()

これらの計算を実行するために使用できるパンダの組み込み関数はありますか?

回答

Terry Aug 21 2020 at 09:27

1つの方法は、最初に、一時DFを使用して、各グループ(['Date'、 'C​​ompany'、 'C​​ountry'])のSold値を1行に統合することです。
その後、あなたの適用.groupbyでは、.rolling8行の間隔で。
合計を計算した後、各行の値を[販売済み]列の値で減算し、その列を元のDFに追加します。.merge

#convert Date column to datetime
df['Date'] = pd.to_datetime(df['Date'], format='%d.%m.%Y')
#create a temporary DataFrame
df2 = df.groupby(['Date', 'Company', 'Country'])['Sold'].sum().reset_index()
#calc the lastweek
df2['LastWeek_Count'] = (df2.groupby(['Company', 'Country'])
                            .rolling(8, min_periods=1, on = 'Date')['Sold']
                            .sum().reset_index(drop=True)
                        ) 
#subtract the value of 'lastweek' from the current 'Sold'
df2['LastWeek_Count'] = df2['LastWeek_Count'] - df2['Sold']
#add th2 new column in the original DF
df.merge(df2.drop(columns=['Sold']), on = ['Date', 'Company', 'Country'])
#output:
    Date        Company Country Sold    LastWeek_Count
0   2020-01-01  A       BE      1       0.0
1   2020-01-02  A       BE      0       1.0
2   2020-01-03  A       BE      1       1.0
3   2020-01-03  A       BE      1       1.0
4   2020-01-04  A       BE      1       3.0
5   2020-01-05  B       DE      1       0.0
6   2020-01-06  B       DE      0       1.0
1 DavidErickson Aug 21 2020 at 07:10

.rollingウィンドウを使用して8から、(グループ化された行ごとに)日付の合計を減算して、過去7日間を効果的に取得できます。このサンプルデータについても、渡す必要がありmin_periods=1ます(そうでない場合はNaN値を取得しますが、実際のデータセットについては、<であるウィンドウで何をするかを決定する必要があります8)。

次に、の.rollingウィンドウから、関連する8.groupbyの列を実行しますが、Date今回も含めてmax、新しく作成されたLastWeek_Count列の値を取得します。max1日に複数のレコードがあるため、を取得する必要があります。したがって、最大を取得することにより、あたりの合計合計量を取得することになりますDate

その後、別にグループ化されとるシリーズ作成sumあたりをDate。最後のステップで、ローリング8日間の最大値から日付ごとの合計を減算します。これは、次のオフセットのパラメーターがないため、過去7日間の合計を取得する方法の回避策です.rolling

df['Date'] = pd.to_datetime(df['Date'], dayfirst=True)
df['LastWeek_Count'] = df.groupby(['Company', 'Country']).rolling(8, min_periods=1, on='Date')['Sold'].sum().reset_index()['Sold']
df['LastWeek_Count'] = df.groupby(['Company', 'Country', 'Date'])['LastWeek_Count'].transform('max')
s = df.groupby(['Company', 'Country', 'Date'])['Sold'].transform('sum')
df['LastWeek_Count'] = (df['LastWeek_Count']-s).astype(int)

Out[17]: 
        Date Company Country  Sold  LastWeek_Count
0 2020-01-01       A      BE     1               0
1 2020-01-02       A      BE     0               1
2 2020-01-03       A      BE     1               1
3 2020-01-03       A      BE     1               1
4 2020-01-04       A      BE     1               3
5 2020-01-05       B      DE     1               0
6 2020-01-06       B      DE     0               1