【问题标题】:Replace NaNs for month N with the value for month (N - 1) in Pandas DataFrame用 Pandas DataFrame 中月份 (N - 1) 的值替换 N 月份的 NaN
【发布时间】:2019-06-24 07:12:36
【问题描述】:

我有一些每月更新的零件的定价数据。它已被拉入熊猫数据框中。有时,某个零件在某个月份无法获得价格,在这种情况下,我想将其替换为该零件上个月的价格。

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

如果没有找到该部分的有效价格,那么我希望将这部分从数据框中完全删除。

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

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

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

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

【问题讨论】:

    标签: python pandas dataframe data-cleaning


    【解决方案1】:

    以下应该有效:

    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
    

    更多细节:

    • 方法链的第一行删除其部件号在任何日期都没有非空价格的所有行
    • 下一行按日期对值进行排序
    • 第 3 行将 'price' 列替换为按组向前填充的列
    • 第 4 行删除空行
    • 最后一行只是为了好看

    如果你希望df按照你显示的顺序,你可以翻转数据框:

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

    【讨论】:

    • 完美运行。谢谢。
    【解决方案2】:

    我认为你需要在这里使用 bfill 而不是 ffill:

    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
    

    【讨论】:

      【解决方案3】:

      如您的问题中所示,您的数据位于数据框 (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
      

      【讨论】:

        猜你喜欢
        • 2020-01-07
        • 2019-12-26
        • 2016-10-04
        • 2019-04-25
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多