【问题标题】:How can I ffill a pandas dataframe based on id and "original date" range?如何根据 id 和“原始日期”范围填充熊猫数据框?
【发布时间】:2021-02-25 15:09:33
【问题描述】:

我有一个 DataFrame,其中有 1000 行和 100 列,我想在其中转发数据,但按 id 和原始数据(日期范围)分组。我所说的原始数据的意思是,如果我们有日期为 01/01/2020 的 id 1 的数据,但日期为 01/05/2020、02/02/2020 的空值,我想在 01/05 填写数据/2020 但不是 02/02/2020,因为 02/02/2020 不在 30 天内。当我们填充时,它会根据最后的结果填充所有数据。

import pandas as pd
import numpy as np

res= pd.DataFrame({'id':[1,1,1,1,1,2,2],
                   'date':['01/01/2020','01/05/2020','02/03/2020','02/05/2020','04/01/2020','01/01/2020','01/02/2020'],
                   'result':[1.5,np.nan,np.nan,2.6,np.nan,np.nan,6.0]})

res['result1']= res.groupby(['id']).apply(lambda x: x.result.ffill()).reset_index(drop=True)

我得到的结果是:

   id        date  result  result1
0   1  01/01/2020     1.5      1.5
1   1  01/05/2020     NaN      1.5
2   1  02/03/2020     NaN      1.5
3   1  02/05/2020     2.6      2.6
4   1  04/01/2020     NaN      2.6
5   2  01/01/2020     NaN      NaN
6   2  01/02/2020     6.0      6.0

我想要的是:

   id        date  result  result1
0   1  01/01/2020     1.5      1.5
1   1  01/05/2020     NaN      1.5
2   1  02/03/2020     NaN      NaN
3   1  02/05/2020     2.6      2.6
4   1  04/01/2020     NaN      NaN
5   2  01/01/2020     NaN      NaN
6   2  01/02/2020     6.0      6.0

【问题讨论】:

  • 请不要将解决方案放在问题中。
  • @BigBen,我遇到了解决方案被删除的帖子,所以想保留它。什么是确保解决方案保持不变的好方法?
  • 接受答案,就像您已经完成的那样。答案空间用于答案,问题空间用于问题。最好保持清洁。

标签: python python-3.x pandas dataframe


【解决方案1】:

你可以试试merge_asof

res['date']=pd.to_datetime(res['date'])
res = res.sort_values('date')
res1 = res.dropna(subset=['result']).rename(columns={'result':'result1'})
out = pd.merge_asof(res.reset_index(),res1 , by ='id', on ='date',tolerance = pd.Timedelta(30, unit='d'),direction = 'backward').sort_values('index')
Out[72]: 
   index  id       date  result  result1
0      0   1 2020-01-01     1.5      1.5
3      1   1 2020-01-05     NaN      1.5
4      2   1 2020-02-03     NaN      NaN
5      3   1 2020-02-05     2.6      2.6
6      4   1 2020-04-01     NaN      NaN
1      5   2 2020-01-01     NaN      NaN
2      6   2 2020-01-02     6.0      6.0

【讨论】:

    【解决方案2】:

    不像 Ben 的 merge_asof 那样优雅,但你可以这样做:

    res['date'] = pd.to_datetime(res['date'])
    
    # valid blocks
    valids = res['result'].notna().cumsum()
    
    # first dates in each block
    first_dates = res.groupby(['id',valids])['date'].transform('min')
    
    # How far we ffill
    mask = (res['date']-first_dates)<pd.Timedelta('30D')
    
    # ffill and then mask
    res['result1'] = res['result'].groupby(res['id']).ffill().where(mask)
    

    输出:

       id       date  result  result1
    0   1 2020-01-01     1.5      1.5
    1   1 2020-01-05     NaN      1.5
    2   1 2020-02-03     NaN      NaN
    3   1 2020-02-05     2.6      2.6
    4   1 2020-04-01     NaN      NaN
    5   2 2020-01-01     NaN      NaN
    6   2 2020-01-02     6.0      6.0
    

    【讨论】:

    • 感谢 Quang 的回复。
    猜你喜欢
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 2016-05-08
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多