2017-09-26 1 views
1

J'ai un tableau avec les ventes et les prévisions par mois pour des milliers de produits à travers 2015 - 2017. Mes données donne la demande & Prévisions pour chaque site, type, produit et date (seulement les moisRemplir tous les mois pour les données multiindex dans pandas

Le problème est que s'il n'y a pas de ventes & aucune prévision dans un mois je ne vois pas la ligne spécifique. Dans l'exemple ci-dessous, vous voyez que la ligne pour "2015-08-31" est manquante. Je voudrais voir pour cette ligne une demande de 0 et une prévision de 0. (Voir ci-dessous un exemple avec df_expected).

Fondamentalement, je voudrais remplir ce tableau avec 0 pour toutes les dates entre 2015-06-30 à 2017-09-30 pour toutes les combinaisons produit/type/site.

Comme vous pouvez le voir dans le code, je n'ai défini aucun index, mais fondamentalement ["Site", "Type", "Product", "Date"] pourrait être vu comme le multiIndex.

Notez que j'ai des millions de lignes.

import pandas as pd 
data = [("W1","G1",1234,pd.to_datetime("2015-07-31"),8,4), 
     ("W1","G1",1234,pd.to_datetime("2015-09-30"),2,4), 
     ("W1","G1",1234,pd.to_datetime("2015-10-31"),2,4), 
     ("W1","G1",1234,pd.to_datetime("2015-11-30"),4,4), 
     ("W1","G2",2345,pd.to_datetime("2015-07-31"),5,0), 
     ("W1","G2",2345,pd.to_datetime("2015-08-31"),1,3), 
     ("W1","G2",2345,pd.to_datetime("2015-10-31"),1,3), 
     ("W1","G2",2345,pd.to_datetime("2015-11-30"),3,3)] 
labels = ["Site","Type","Product","Date","Demand","Forecast"] 
df = pd.DataFrame(data,columns=labels) 
df 

    Site Type Product  Date Demand Forecast 
0 W1 G1  1234 2015-07-31  8   4 
1 W1 G1  1234 2015-09-30  2   4 
2 W1 G1  1234 2015-10-31  2   4 
3 W1 G1  1234 2015-11-30  4   4 
4 W1 G2  2345 2015-07-31  5   0 
5 W1 G2  2345 2015-08-31  1   3 
6 W1 G2  2345 2015-10-31  1   3 
7 W1 G2  2345 2015-11-30  3   3 

Ceci est le résultat que je attends

data_expected = [("W1","G1",1234,pd.to_datetime("2015-07-31"),8,4), 
       ("W1","G1",1234,pd.to_datetime("2015-08-31"),0,0), 
       ("W1","G1",1234,pd.to_datetime("2015-09-30"),2,4),   
       ("W1","G1",1234,pd.to_datetime("2015-10-31"),2,4), 
       ("W1","G1",1234,pd.to_datetime("2015-11-30"),4,4)] 
df_expected = pd.DataFrame(data_expected,columns=labels) 
df_expected 

    Site Type Product  Date Demand Forecast 
0 W1 G1  1234 2015-07-31  8   4 
1 W1 G1  1234 2015-08-31  0   0 
2 W1 G1  1234 2015-09-30  2   4 
3 W1 G1  1234 2015-10-31  2   4 
4 W1 G1  1234 2015-11-30  4   4 

Je pensais à l'origine à propos de la pile/désempiler pour vous assurer que j'ai tous les mois. Mais ce n'est pas optimal pour une base de données avec des millions de lignes.

df = (df 
     .set_index("Date") 
     .groupby(["Site","Product","Type",pd.TimeGrouper('M')])[["Forecast","Demand"]].sum() 
     .unstack() 
     .fillna(0) 
     .astype(int)) 

Qu'en pensez-vous?

Répondre

1

Vous pouvez utiliser DataFrameGroupBy.resample avec asfreq:

df = (df.set_index('Date') 
     .groupby(["Site","Type","Product"])['Demand','Forecast'] 
     .resample('M') 
     .asfreq() 
     .fillna(0) 
     .astype(int) 
     .reset_index()) 
print (df) 
    Site Type Product  Date Demand Forecast 
0 W1 G1  1234 2015-07-31  8   4 
1 W1 G1  1234 2015-08-31  0   0 
2 W1 G1  1234 2015-09-30  2   4 
3 W1 G1  1234 2015-10-31  2   4 
4 W1 G1  1234 2015-11-30  4   4 

EDIT:

J'essaie un peu d'améliorer solution originale avec le paramètre fill_value dans unstack:

(df.set_index("Date") 
    .groupby(["Site","Product","Type",pd.TimeGrouper('M')])['Dem‌​and','Forecast'].sum‌​() 
    .unstack(fill_value=0) 
    .stack()) 
+0

Il semble que ma solution avec pile/Désempiler est plus rapide. Avec ta technique cela fonctionne pour df avec 10 000 lignes. Mais si vous exécutez cela sur 1 million de lignes cela prend beaucoup de temps (je n'ai jamais vu la solution) – Nicolas

+0

Maintenant, je comprends. Je peux seulement améliorer votre solution - '(df.set_index (" Date ") .groupby ([" Site "," Produit "," Type ", pd.TimeGrouper ('M')]) ['Demande', ' Prévision ']. Sum() .unstack (fill_value = 0) .stack()) '- Est-il plus rapide avec vos données réelles? Si oui, je peux l'ajouter à ma réponse. – jezrael

+0

oui c'est beaucoup plus rapide avec ce désempilage/pile – Nicolas

0

La pile/approche Défaire semble travailler beaucoup plus vite. avec ce tous les éléments ont la même date de début et de fin

df = (df.set_index("Date") 
     .groupby(["Site","Product","Type",pd.TimeGrouper('M')])['Demand','Forecast'].sum() 
     .unstack() 
     .fillna(0) 
     .astype(int) 
     .stack()) 


           Demand Forecast 
Site Product Type Date       
W1 1234 G1 2015-07-31  8   4 
        2015-08-31  0   0 
        2015-09-30  2   4 
        2015-10-31  2   4 
        2015-11-30  4   4 
    2345 G2 2015-07-31  5   0 
        2015-08-31  1   3 
        2015-09-30  0   0 
        2015-10-31  1   3 
        2015-11-30  3   3 
+0

Pouvez-vous sortir de votre solution avec des données de test? Pour moi, il retourne le même dataframe que l'original. Peut-être problème avec la version pandas, j'utilise les pandas 0.20.3. – jezrael

+0

Donc, je comprends votre problème. Le problème ici est que si vous ne remplissez que 4 lignes de données, cette solution spécifique ne fonctionnera pas car elle ne remplit aucun mois supplémentaire.Mais si vous exécutez cela sur des lignes de 1m, alors il obtient tous les bons mois. Je vais changer les données initiales pour refléter cela. – Nicolas