用Pandas DataFrame中月份(N-1)的值替换月份N的NaN

时间:2019-01-30 21:59:04

标签: python pandas dataframe data-cleaning data-cleansing

我有一些每月更新的零件价格数据。它已被拉入熊猫数据框。有时候,某个零件在某个月不会获得价格,在这种情况下,我想用上个月的该零件的价格代替它。

如果上个月该部分的价格也缺失,我想继续向后搜索直到找到有效价格,在这种情况下,该价格应向前传播直到找到有效价格。

如果未找到该零件的有效价格,则我希望将该零件完全从数据框中删除。

如果前几个月包含某个部分的缺失价格,我想删除这些行,以便第一条记录始终是有效价格。

基本上,我想在价格栏上进行前向填充,但要考虑零件号。

作为一个例子,我将从这样的事情开始:

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

并以此结尾:

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

3 个答案:

答案 0 :(得分:2)

以下方法应该起作用:

myLogin

结果:

const myLogin = (credentials) => {
    console.log('1: myLogin fired',credentials)
    const {firebase} = this.props;
    console.log('2: myLogin -> firebase',firebase)

    try {
        console.log('3: async -> myLogin -> firebase: ', firebase)
        await firebase.auth().signInWithEmailAndPassword(credentials.email, 
            credentials.password);
        console.log('try fired')
    } catch (error) {
        console.log(error);
        throw new SubmissionError({
            _error: 'Login failed'
        })
    }
}

更多细节:

  • 方法链的第一行删除所有部件号在任何日期的价格都不为空的行
  • 下一行按日期对值进行排序
  • 的第三线按组以正填充的一个替换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)
  • 第四行删除带有空值的行
  • 最后一行仅用于外观

如果要按照显示的顺序 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 ,可以翻转数据框:

'price'

答案 1 :(得分:1)

我认为您需要在此处使用填充而不是填充:

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

因此更新价格列:

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

现在,您可以使用NaN价格删除那些商品:

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

答案 2 :(得分:0)

将数据放在问题中上面显示的数据框(df)中,您可以使用以下方法获得结果:

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

在我的情况下,您的答案在数据透视表中。

   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