Grupo de pandas y ventana móvil
Estoy tratando de calcular la suma de un campo durante un período de tiempo específico, después de aplicar la función de agrupación.
Mi conjunto de datos se ve así:
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
Me gustaría agregar una nueva columna por cada fila, que calcule la suma de Vendido (por cada grupo "Empresa, País" durante los últimos 7 días, sin incluir el día actual
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
Intenté lo siguiente, pero también incluye la fecha actual y da valores diferentes para la misma fecha, es decir, 03.01.2020
df['LastWeek_Count'] = df.groupby(['Company', 'Country']).rolling(7, on ='Date')['Sold'].sum().reset_index()
¿Hay una función de compilación en pandas que pueda usar para realizar estos cálculos?
Respuestas
Una forma sería consolidar primero el valor Vendido de cada grupo (['Fecha', 'Compañía', 'País']) en una sola línea usando un DF temporal.
Después de eso, aplique su .groupby
con .rolling
un intervalo de 8 filas.
Después de calcular la suma, reste el valor de cada línea con el valor en la columna Vendido y agregue esa columna en el DF original 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
Puede usar una .rolling
ventana de 8
y luego restar la suma de la Fecha (para cada fila agrupada) para obtener efectivamente los 7 días anteriores. Para estos datos de muestra, también debemos pasar min_periods=1
(de lo contrario, obtendrá NaN
valores, pero para su conjunto de datos real, deberá decidir qué desea hacer con las ventanas que son < 8
).
Luego, desde la .rolling
ventana de 8
, simplemente haga otra .groupby
de las columnas relevantes pero también incluya Date
esta vez y tome el max
valor de la LastWeek_Count
columna recién creada. Debe tomar el max
, porque tiene varios registros por día, por lo que al tomar el máximo, está tomando la cantidad total agregada por Date
.
Luego, cree una serie que tome el agrupado por sum
por Date
. En el paso final, reste la suma por fecha del máximo móvil de 8 días, que es una solución para obtener la suma de los 7 días anteriores, ya que no hay un parámetro para una compensación 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