Pandas groupby e finestra scorrevole
Sto cercando di calcolare la somma di un campo per un periodo di tempo specifico, dopo l'applicazione della funzione di raggruppamento.
Il mio set di dati è simile a questo:
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
Vorrei aggiungere una nuova colonna per ogni riga, che calcola la somma dei Venduti (per ogni gruppo "Azienda, Paese" per gli ultimi 7 giorni - escluso il giorno corrente
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
Ho provato quanto segue, ma include anche la data corrente e fornisce valori diversi per la stessa data, ad esempio 03.01.2020
df['LastWeek_Count'] = df.groupby(['Company', 'Country']).rolling(7, on ='Date')['Sold'].sum().reset_index()
Esiste una funzione incorporata nei panda che posso utilizzare per eseguire questi calcoli?
Risposte
Un modo potrebbe essere quello di consolidare prima il valore Venduto di ciascun gruppo (['Data', 'Azienda', 'Paese']) su una singola riga utilizzando un DF temporaneo.
Successivamente, applica il tuo .groupby
con .rolling
con un intervallo di 8 righe.
Dopo aver calcolato la somma, sottrai il valore di ogni riga con il valore nella colonna Venduto e aggiungi quella colonna nel DF originale con.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
È possibile utilizzare una .rolling
finestra di 8
e quindi sottrarre la somma della data (per ogni riga raggruppata) per ottenere effettivamente i 7 giorni precedenti. Per questi dati di esempio, dovremmo anche passare min_periods=1
(altrimenti otterrai NaN
valori, ma per il tuo set di dati effettivo, dovrai decidere cosa vuoi fare con le finestre che sono < 8
).
Quindi dalla .rolling
finestra di 8
, fai semplicemente un'altra .groupby
delle colonne pertinenti ma includi anche Date
questa volta e prendi il max
valore della LastWeek_Count
colonna appena creata. Devi prendere il max
, perché hai più record al giorno, quindi prendendo il massimo, stai prendendo l'importo totale aggregato per Date
.
Quindi, crea una serie che prenda il raggruppamento per sum
per Date
. Nel passaggio finale sottrarre la somma per data dal massimo di 8 giorni in movimento, che è una soluzione alternativa a come è possibile ottenere la somma dei 7 giorni precedenti, in quanto non esiste un parametro per un offset con .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