3
votes

Remplacez NaN pour le mois N par la valeur pour le mois (N - 1) dans Pandas DataFrame

J'ai des données de prix pour les pièces qui sont mises à jour tous les mois. Il a été intégré à un dataframe pandas. Parfois, une pièce ne recevra pas de prix pendant un certain mois, auquel cas je voudrais la remplacer par le prix de cette pièce du mois précédent.

Dans le cas où le mois précédent a également un prix manquant pour cette pièce, je souhaite continuer à chercher en arrière jusqu'à ce qu'un prix valide soit trouvé, auquel cas ce prix devrait se propager jusqu'à ce qu'un prix valide soit trouvé.

Si aucun prix valide n'est trouvé pour cette pièce, je souhaite que cette pièce soit entièrement supprimée de la base de données.

Si le premier nombre de mois contient des prix manquants pour une certaine partie, je voudrais supprimer ces lignes afin que le premier enregistrement soit toujours un prix valide.

Essentiellement, je veux remplir la colonne de prix en tenant compte des numéros de pièce.

À titre d'exemple, je commencerais par quelque chose comme ceci:

part   price      date
1      67.32      2018-12-01 00:00:00.000
3      99.16      2018-12-01 00:00:00.000
1      67.32      2018-11-01 00:00:00.000
3      167.34     2018-11-01 00:00:00.000
1      67.32      2018-10-01 00:00:00.000
3      167.34     2018-10-01 00:00:00.000
1      88.37      2018-09-01 00:00:00.000
3      212.70     2018-09-01 00:00:00.000
1      88.37      2018-08-01 00:00:00.000
3      264.02     2018-08-01 00:00:00.000
1      88.37      2018-07-01 00:00:00.000
3      264.02     2018-07-01 00:00:00.000

Et terminer par ceci:

part   price      date
1      NaN        2018-12-01 00:00:00.000
2      NaN        2018-12-01 00:00:00.000
3      99.16      2018-12-01 00:00:00.000
1      NaN        2018-11-01 00:00:00.000
2      NaN        2018-11-01 00:00:00.000
3      NaN        2018-11-01 00:00:00.000
1      67.32      2018-10-01 00:00:00.000
2      NaN        2018-10-01 00:00:00.000
3      167.34     2018-10-01 00:00:00.000
1      88.37      2018-09-01 00:00:00.000
2      NaN        2018-09-01 00:00:00.000
3      212.70     2018-09-01 00:00:00.000
1      88.37      2018-08-01 00:00:00.000
2      NaN        2018-08-01 00:00:00.000
3      NaN        2018-08-01 00:00:00.000
1      88.37      2018-07-01 00:00:00.000
2      NaN        2018-07-01 00:00:00.000
3      264.02     2018-07-01 00:00:00.000
1      NaN        2018-06-01 00:00:00.000


0 commentaires

3 Réponses :


2
votes

Ce qui suit devrait fonctionner:

df = df.iloc[::-1].reset_index(drop=True)

Résultat:

    part    price   date
0   1   88.37   2018-07-01
1   3   264.02  2018-07-01
2   1   88.37   2018-08-01
3   3   264.02  2018-08-01
4   1   88.37   2018-09-01
5   3   212.70  2018-09-01
6   1   67.32   2018-10-01
7   3   167.34  2018-10-01
8   1   67.32   2018-11-01
9   3   167.34  2018-11-01
10  1   67.32   2018-12-01
11  3   99.16   2018-12-01

Un peu plus de détails:

  • La première ligne de la chaîne de méthodes supprime toutes les lignes dont les numéros de pièce n'ont pas de prix non nul pour aucune date
  • La ligne suivante trie les valeurs par date
  • La troisième ligne remplace la colonne 'price' par une colonne remplie à terme par groupe
  • La 4ème ligne supprime les lignes avec des valeurs nulles
  • La dernière ligne est juste pour les looks

Si vous voulez le df dans l'ordre que vous avez montré, vous pouvez retourner le dataframe:

df.loc[lambda df: df.groupby('part')['price'].transform(np.any)]\
  .sort_values('date')\
  .assign(price=lambda df: df.groupby('part')['price'].ffill())\
  .dropna()\
  .reset_index(drop=True)


1 commentaires

Marche parfaitement. Merci.



1
votes

Je pense que vous devez utiliser bfill plutôt que remplir ici:

In [14]: df = df.dropna(subset=['price'])

In [15]: df
Out[15]:
    part   price                     date
0      1   67.32  2018-12-01 00:00:00.000
2      3   99.16  2018-12-01 00:00:00.000
3      1   67.32  2018-11-01 00:00:00.000
5      3  167.34  2018-11-01 00:00:00.000
6      1   67.32  2018-10-01 00:00:00.000
8      3  167.34  2018-10-01 00:00:00.000
9      1   88.37  2018-09-01 00:00:00.000
11     3  212.70  2018-09-01 00:00:00.000
12     1   88.37  2018-08-01 00:00:00.000
14     3  264.02  2018-08-01 00:00:00.000
15     1   88.37  2018-07-01 00:00:00.000
17     3  264.02  2018-07-01 00:00:00.000

Mettez donc à jour la colonne de prix:

In [12]: df['price'] = df.groupby('part')['price'].bfill()

In [13]: df
Out[13]:
    part   price                     date
0      1   67.32  2018-12-01 00:00:00.000
1      2     NaN  2018-12-01 00:00:00.000
2      3   99.16  2018-12-01 00:00:00.000
3      1   67.32  2018-11-01 00:00:00.000
4      2     NaN  2018-11-01 00:00:00.000
5      3  167.34  2018-11-01 00:00:00.000
6      1   67.32  2018-10-01 00:00:00.000
7      2     NaN  2018-10-01 00:00:00.000
8      3  167.34  2018-10-01 00:00:00.000
9      1   88.37  2018-09-01 00:00:00.000
10     2     NaN  2018-09-01 00:00:00.000
11     3  212.70  2018-09-01 00:00:00.000
12     1   88.37  2018-08-01 00:00:00.000
13     2     NaN  2018-08-01 00:00:00.000
14     3  264.02  2018-08-01 00:00:00.000
15     1   88.37  2018-07-01 00:00:00.000
16     2     NaN  2018-07-01 00:00:00.000
17     3  264.02  2018-07-01 00:00:00.000
18     1     NaN  2018-06-01 00:00:00.000

Vous pouvez maintenant supprimer ceux avec un prix NaN:

In [11]: df.groupby('part')['price'].bfill()
Out[11]:
0      67.32
1        NaN
2      99.16
3      67.32
4        NaN
5     167.34
6      67.32
7        NaN
8     167.34
9      88.37
10       NaN
11    212.70
12     88.37
13       NaN
14    264.02
15     88.37
16       NaN
17    264.02
18       NaN
Name: price, dtype: float64


0 commentaires

0
votes

Avec vos données dans un dataframe (df) comme indiqué ci-dessus dans votre question, vous pouvez utiliser ce qui suit pour obtenir votre résultat:

   part       1       3
date        
2018-12-01  67.32   99.16
2018-11-01  67.32   167.34
2018-10-01  67.32   167.34
2018-09-01  88.37   212.70
2018-08-01  88.37   264.02
2018-07-01  88.37   264.02

Dans mon cas, votre réponse est dans un tableau croisé dynamique toutefois.

df = df.pivot_table('price', index='date', columns ='part').fillna(method='ffill')
df.dropna().sort_index(ascending=False)


0 commentaires