4 votes

pandas - agréger une partie d'une colonne pour obtenir une nouvelle valeur dans une nouvelle colonne

J'ai un grand pandas Cadre de données df avec des données d'entrepôt montrant les quantités d'articles reçus.

Imaginez la partie pertinente de la structure comme :

Date         SKU    received
2017-05-29   sku1   0
2017-05-30   sku1   0
2017-05-31   sku1   0
2017-06-01   sku1   0
2017-06-02   sku1   6
2017-06-03   sku1   2
2017-05-29   sku2   4
2017-05-30   sku2   4
2017-05-31   sku2   0
2017-06-01   sku2   0
2017-06-02   sku2   0
2017-06-03   sku2   24

A partir de là, je voudrais reconstituer le processus de commande. Je sais que le niveau de stock est examiné le lundi et que de nouvelles commandes sont passées en fonction de ce niveau. Les commandes arrivent à l'entrepôt environ une semaine plus tard, parfois divisées en plusieurs expéditions.

J'ai pensé à créer une colonne supplémentaire pour les jours de la semaine ( df["Weekday"] ) et pour les commandes passées ( df["Order"] ). Sur la base du jour de la semaine, je voudrais agréger les données de la colonne "reçu" pour les 4 à 11 jours suivants, en me limitant à l'UGS concernée.

Le résultat pourrait ressembler à ceci :

Date         SKU    received    Weekday    Order
2017-05-29   sku1   0           0          8
2017-05-30   sku1   0           1          0
2017-05-31   sku1   0           2          0  
2017-06-01   sku1   0           3          0
2017-06-02   sku1   6           4          0
2017-06-03   sku1   2           5          0
2017-05-29   sku2   4           0          24
2017-05-30   sku2   4           1          0
2017-05-31   sku2   0           2          0
2017-06-01   sku2   0           3          0
2017-06-02   sku2   0           4          0
2017-06-03   sku2   24          5          0

Voici le code que j'ai essayé :

import pandas as pd

# 0 is Monday, 1 is Tuesday, etc
df["Weekday"] = df["Date"].dt.dayofweek

# create new column for the orders
df["Order"] = 0

min_days = 4
max_days = min_days + 7

for i in range(len(df)):
    if df.loc[i, "Weekday"] == 0:
        df.loc[i, "Order"] = df.loc[(df.Date >= df.loc[i, "Date"] + pd.to_timedelta(min_days, unit="D")) &
                                    (df.Date < df.loc[i, "Date"] + pd.to_timedelta(max_days, unit="D")) &
                                    (df.SKU == df.loc[i, "SKU"]), "received"].sum()

Il semble faire le travail, mais de manière lente. Peut-être que quelqu'un peut m'aider à trouver une approche plus pythonique/pandas pour gagner du temps de calcul.

Merci pour votre aide.

1voto

FLab Points 3543

Voici une solution possible qui utilise pandas groupby et transform.

La première idée est que l'on peut obtenir le décompte entre deux jours en prenant la différence des sommes roulantes. Notez également l'astuce consistant à inverser l'ordre ( [::-1] ) deux fois afin d'avoir une somme glissante prélevant des jours dans le futur.

def count_between(ts, min_days, max_days):
    return ts[::-1].pipe(lambda y: y.rolling(max_days,1).sum() - y.rolling(min_days-1,1).sum())[::-1]

Cette fonction vous donnerait des résultats pour chaque jour, de sorte que vous limitez les résultats aux lundis en mettant toutes les autres entrées à 0 (en utilisant [.where][1] ).

Après le réglage Date en tant qu'index, vous pouvez procéder comme suit :

order = df.groupby('SKU')\
          .transform(lambda x: count_between(x, min_days, max_days)\
                               .where(lambda y: y.index.dayofweek==0, other = 0))
order.columns = ['Order']

Cela donne le résultat attendu :

pd.concat([df, order], axis = 1)
Out[319]: 
             SKU  received  Order
Date                             
2017-05-29  sku1         0    8.0
2017-05-30  sku1         0    0.0
2017-05-31  sku1         0    0.0
2017-06-01  sku1         0    0.0
2017-06-02  sku1         6    0.0
2017-06-03  sku1         2    0.0
2017-05-29  sku2         4   24.0
2017-05-30  sku2         4    0.0
2017-05-31  sku2         0    0.0
2017-06-01  sku2         0    0.0
2017-06-02  sku2         0    0.0
2017-06-03  sku2        24    0.0

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X