【问题标题】:Fill missing date for each group and impute empty values in Pandas填写每个组的缺失日期并在 Pandas 中估算空值
【发布时间】:2019-12-25 10:39:57
【问题描述】:

对于以下数据框,我如何填写每个组 citydistrict 的缺失日期,假设完整日期范围是从 2019/1/12019/6/1,然后用 values 填空 @987654326 @s 前后单元格,如果前后都没有值,则使用bfillffill

   city district      date  value
0     a        d  2019/1/1   9.99
1     a        d  2019/2/1  10.66
2     a        d  2019/3/1  10.56
3     a        d  2019/4/1  10.06
4     a        d  2019/5/1  10.69
5     a        d  2019/6/1  10.77
6     b        e  2019/1/1   9.72
7     b        e  2019/2/1   9.72
8     b        e  2019/4/1   9.78
9     b        e  2019/5/1   9.76
10    b        e  2019/6/1   9.66
11    c        f  2019/4/1   9.57
12    c        f  2019/5/1   9.47
13    c        f  2019/6/1   9.39

预期的结果是这样的:

   city district      date  value
0     a        d  2019/1/1   9.99
1     a        d  2019/2/1  10.66
2     a        d  2019/3/1  10.56
3     a        d  2019/4/1  10.06
4     a        d  2019/5/1  10.69
5     a        d  2019/6/1  10.77
6     b        e  2019/1/1   9.72
7     b        e  2019/2/1   9.72
8     b        e  2019/3/1   9.75
9     b        e  2019/4/1   9.78
10    b        e  2019/5/1   9.76
11    b        e  2019/6/1   9.66
12    c        f  2019/1/1   9.57
13    c        f  2019/2/1   9.57
14    c        f  2019/3/1   9.57
15    c        f  2019/4/1   9.57
16    c        f  2019/5/1   9.47
17    c        f  2019/6/1   9.39

如何在 Pandas 中做到这一点?非常感谢。

更新: 当我添加freq = 'M'时,都变成NaNs。

df['date']=pd.to_datetime(df['date'])
( df.set_index('date')
  .groupby(['city','district'],as_index=False)
  .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max(), freq = 'M'))
                    .interpolate()
                    .bfill()
                    .ffill())
  .rename_axis(index = [0,'date'])
  .reset_index()
  .drop(0,axis=1)
)

输出:

         date  city  district  value
0  2019-01-31   NaN       NaN    NaN
1  2019-02-28   NaN       NaN    NaN
2  2019-03-31   NaN       NaN    NaN
3  2019-04-30   NaN       NaN    NaN
4  2019-05-31   NaN       NaN    NaN
5  2019-01-31   NaN       NaN    NaN
6  2019-02-28   NaN       NaN    NaN
7  2019-03-31   NaN       NaN    NaN
8  2019-04-30   NaN       NaN    NaN
9  2019-05-31   NaN       NaN    NaN
10 2019-01-31   NaN       NaN    NaN
11 2019-02-28   NaN       NaN    NaN
12 2019-03-31   NaN       NaN    NaN
13 2019-04-30   NaN       NaN    NaN
14 2019-05-31   NaN       NaN    NaN

【问题讨论】:

    标签: python-3.x pandas dataframe datetime


    【解决方案1】:

    我们可以这样做:

    df['date']=pd.to_datetime(df['date'],format ='%YYYY/%dd/%mm' )
    

    ( df.set_index('date')
      .groupby(['city','district'],as_index=False)
      .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max()))
                        .interpolate()
                        .bfill()
                        .ffill())
      .rename_axis(index = [0,'date'])
      .reset_index()
      .drop(0,axis=1)
    
    )
    

    输出

                      date city district  value
    0  2019-01-01 00:01:00    a        d   9.99
    1  2019-01-02 00:01:00    a        d  10.66
    2  2019-01-03 00:01:00    a        d  10.56
    3  2019-01-04 00:01:00    a        d  10.06
    4  2019-01-05 00:01:00    a        d  10.69
    5  2019-01-06 00:01:00    a        d  10.77
    6  2019-01-01 00:01:00    b        e   9.72
    7  2019-01-02 00:01:00    b        e   9.72
    8  2019-01-03 00:01:00    b        e   9.75
    9  2019-01-04 00:01:00    b        e   9.78
    10 2019-01-05 00:01:00    b        e   9.76
    11 2019-01-06 00:01:00    b        e   9.66
    12 2019-01-01 00:01:00    c        f   9.57
    13 2019-01-02 00:01:00    c        f   9.57
    14 2019-01-03 00:01:00    c        f   9.57
    15 2019-01-04 00:01:00    c        f   9.57
    16 2019-01-05 00:01:00    c        f   9.47
    17 2019-01-06 00:01:00    c        f   9.39
    

    【讨论】:

    • 能否添加输出?
    • 我们可以使用( df.set_index('date') .groupby(['city','district'],as_index=False)['value'] .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max())) .interpolate() .bfill() .ffill()) .rename_axis(index = [0,'date']) .reset_index() .drop(0,axis=1) )吗?我的真实数据有超过value列,应用你的代码后它变成了所有NaNs。
    • 抱歉,刚注意到一个问题,我的预期日期按月增加,但您的输出按日期增加。
    【解决方案2】:

    如果每组只有NaNs 值,您可以更改解决方案,为每组替换错误值以避免错误替换:

    df['date']=pd.to_datetime(df['date'])
    
    rng = pd.date_range('2019-01-01', '2019-06-01', freq='MS')
    c = df['city'].unique()
    mux = pd.MultiIndex.from_product([c, rng], names=['city', 'date'])
    
    df1 = (df.set_index(['city', 'date']).reindex(mux, method='ffill')
           .groupby(level=0)
           .apply(lambda x: x.bfill().ffill())
           .reset_index())
    print (df1)
       city       date district  value
    0     a 2019-01-01        d   9.99
    1     a 2019-02-01        d  10.66
    2     a 2019-03-01        d  10.56
    3     a 2019-04-01        d  10.06
    4     a 2019-05-01        d  10.69
    5     a 2019-06-01        d  10.77
    6     b 2019-01-01        e   9.72
    7     b 2019-02-01        e   9.72
    8     b 2019-03-01        e   9.72
    9     b 2019-04-01        e   9.78
    10    b 2019-05-01        e   9.76
    11    b 2019-06-01        e   9.66
    12    c 2019-01-01        e   9.66
    13    c 2019-02-01        e   9.66
    14    c 2019-03-01        e   9.66
    15    c 2019-04-01        f   9.57
    16    c 2019-05-01        f   9.47
    17    c 2019-06-01        f   9.39
    

    或者使用带有reindexmethod='bfill'的自定义函数:

    df2 = (df.set_index('date')
             .groupby(['city','district'], group_keys=False)
             .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max(), freq='MS'), method='bfill')
                               .ffill())
             .rename_axis('date')
             .reset_index())
    print (df2)
             date city district  value
    0  2019-01-01    a        d   9.99
    1  2019-02-01    a        d  10.66
    2  2019-03-01    a        d  10.56
    3  2019-04-01    a        d  10.06
    4  2019-05-01    a        d  10.69
    5  2019-06-01    a        d  10.77
    6  2019-01-01    b        e   9.72
    7  2019-02-01    b        e   9.72
    8  2019-03-01    b        e   9.78
    9  2019-04-01    b        e   9.78
    10 2019-05-01    b        e   9.76
    11 2019-06-01    b        e   9.66
    12 2019-01-01    c        f   9.57
    13 2019-02-01    c        f   9.57
    14 2019-03-01    c        f   9.57
    15 2019-04-01    c        f   9.57
    16 2019-05-01    c        f   9.47
    17 2019-06-01    c        f   9.39 
    

    interpolate 的解决方案:

    df2 = (df.set_index('date')
             .groupby(['city','district'], group_keys=False)
             .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max(), freq='MS'))
                               .interpolate()
                               .bfill()
                               .ffill())
             .rename_axis('date')
             .reset_index())
    print (df2)
             date city district  value
    0  2019-01-01    a        d   9.99
    1  2019-02-01    a        d  10.66
    2  2019-03-01    a        d  10.56
    3  2019-04-01    a        d  10.06
    4  2019-05-01    a        d  10.69
    5  2019-06-01    a        d  10.77
    6  2019-01-01    b        e   9.72
    7  2019-02-01    b        e   9.72
    8  2019-03-01    b        e   9.75
    9  2019-04-01    b        e   9.78
    10 2019-05-01    b        e   9.76
    11 2019-06-01    b        e   9.66
    12 2019-01-01    c        f   9.57
    13 2019-02-01    c        f   9.57
    14 2019-03-01    c        f   9.57
    15 2019-04-01    c        f   9.57
    16 2019-05-01    c        f   9.47
    17 2019-06-01    c        f   9.39
    

    EDIT1:仅针对一列的解决方案:

    df2 = (df.set_index('date')
             .groupby(['city','district'])['value']
             .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max(), freq='MS'))
                               .interpolate()
                               .bfill()
                               .ffill())
             .rename_axis(['city','district','date'])
             .reset_index())
    print (df2)
       city district       date  value
    0     a        d 2019-01-01   9.99
    1     a        d 2019-02-01  10.66
    2     a        d 2019-03-01  10.56
    3     a        d 2019-04-01  10.06
    4     a        d 2019-05-01  10.69
    5     a        d 2019-06-01  10.77
    6     b        e 2019-01-01   9.72
    7     b        e 2019-02-01   9.72
    8     b        e 2019-03-01   9.75
    9     b        e 2019-04-01   9.78
    10    b        e 2019-05-01   9.76
    11    b        e 2019-06-01   9.66
    12    c        f 2019-01-01   9.57
    13    c        f 2019-02-01   9.57
    14    c        f 2019-03-01   9.57
    15    c        f 2019-04-01   9.57
    16    c        f 2019-05-01   9.47
    17    c        f 2019-06-01   9.39  
    

    【讨论】:

    • 非常感谢,在您的第二个解决方案中,是否可以添加.interpolate()
    • @ahbon - 是的,只需要删除 reindex 中的 method 参数以获取缺失值
    • 另一个问题,如果我想使用applylambda 函数仅value1 列,如果df 有其他列value2, value3, value4, ect. 我试过df.set_index('date') .groupby(['city','district'], group_keys=False)['value1'] .apply(lambda x: x.reindex(pd.date_range(df.date.min(),df.date.max(), freq='MS'), method='bfill') .ffill()) .rename_axis('date') .reset_index()。它不起作用。
    • @ahbon - 已编辑解决方案以仅处理一列 value。输出中的所有其他列都将被删除。
    • 太好了,这要快得多。
    【解决方案3】:

    这个解决方案:

    df['date']=pd.to_datetime(df['date'])
    
    rng = pd.date_range('2019-01-01', '2019-06-01', freq='MS')
    c = df['city'].unique()
    mux = pd.MultiIndex.from_product([c, rng], names=['city', 'date'])
    
    
    print(df.set_index(['city', 'date']).reindex(mux).groupby(level=0)\
            .bfill()\
            .ffill()\
            .reset_index())
    

    输出:

       city       date district  value
    0     a 2019-01-01        d   9.99
    1     a 2019-02-01        d  10.66
    2     a 2019-03-01        d  10.56
    3     a 2019-04-01        d  10.06
    4     a 2019-05-01        d  10.69
    5     a 2019-06-01        d  10.77
    6     b 2019-01-01        e   9.72
    7     b 2019-02-01        e   9.72
    8     b 2019-03-01        e   9.78
    9     b 2019-04-01        e   9.78
    10    b 2019-05-01        e   9.76
    11    b 2019-06-01        e   9.66
    12    c 2019-01-01        f   9.57
    13    c 2019-02-01        f   9.57
    14    c 2019-03-01        f   9.57
    15    c 2019-04-01        f   9.57
    16    c 2019-05-01        f   9.47
    17    c 2019-06-01        f   9.39
    

    【讨论】:

      猜你喜欢
      • 2019-05-19
      • 2020-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-15
      • 1970-01-01
      相关资源
      最近更新 更多