首页 文章

基于组和前一行pandas的前向填充(ffill)

提问于
浏览
0

我有一个大型数据帧(400,000行),如下所示:

data = np.array([
          [1949, '01/01/2018', np.nan, 17,     '30/11/2017'],
          [1949, '01/01/2018', np.nan, 19,      np.nan],
          [1811, '01/01/2018',     16, np.nan, '31/11/2017'],
          [1949, '01/01/2018',     15, 21,     '01/12/2017'],
          [1949, '01/01/2018', np.nan, 20,      np.nan],
          [3212, '01/01/2018',     21, 17,     '31/11/2017']
         ])
columns = ['id', 'ReceivedDate', 'PropertyType', 'MeterType', 'VisitDate']
pd.DataFrame(data, columns=columns)

结果df:

id     ReceivedDate    PropertyType    MeterType   VisitDate
0   1949    01/01/2018       NaN              17       30/11/2017
1   1949    01/01/2018       NaN              19       NaN
2   1811    01/01/2018       16              NaN       31/11/2017
3   1949    01/01/2018       15               21       01/12/2017
4   1949    01/01/2018       NaN              20       NaN
5   3212    01/01/2018       21               17       31/11/2017

我想基于groupby(id和接收日期)转发填充 - 只要它们在索引中按顺序进入(即只有前向填充索引位置1和4) .

我想有一个专栏,说明是否应根据标准填写,但我如何查看上面的行?

(我计划使用这个答案的解决方案:pandas fill forward performance issue

df.isnull().astype(int)).groupby(level=0).cumsum().applymap(lambda x: None if x == 0 else 1)

因为 x = df.groupby(['id','ReceivedDate']).ffill() 非常慢 . )

所需的df:

id     ReceivedDate    PropertyType    MeterType   VisitDate
0   1949    01/01/2018       NaN              17       30/11/2017
1   1949    01/01/2018       NaN              19       30/11/2017
2   1811    01/01/2018       16              NaN       31/11/2017
3   1949    01/01/2018       15               21       01/12/2017
4   1949    01/01/2018       15               20       01/12/2017
5   3212    01/01/2018       21               17       31/11/2017

2 回答

  • 1

    Option 1
    groupby ffilllimit=1 -

    df.groupby(['id', 'ReceivedDate']).ffill(limit=1)
    
         id ReceivedDate PropertyType MeterType   VisitDate
    0  1949   01/01/2018          NaN        17  30/11/2017
    1  1949   01/01/2018          NaN        19  30/11/2017
    2  1811   01/01/2018           16        18  31/11/2017
    3  1949   01/01/2018           15        21  01/12/2017
    4  1949   01/01/2018           15        20  01/12/2017
    5  3212   01/01/2018           21        17  31/11/2017
    

    Option 2
    代替 groupby ffill ,尝试用 groupbymaskshift 填充NaNs -

    i = df[['id', 'ReceivedDate']]
    j = i.ne(i.shift().values).any(1).cumsum()
    
    df.mask(df.isnull().astype(int).groupby(j).cumsum().eq(1), df.groupby(j).shift())
    

    要么,

    df.where(df.isnull().astype(int).groupby(j).cumsum().ne(1), df.groupby(j).shift())
    
    id ReceivedDate PropertyType MeterType   VisitDate
    0  1949   01/01/2018          NaN        17  30/11/2017
    1  1949   01/01/2018          NaN        19  30/11/2017
    2  1811   01/01/2018           16        18  31/11/2017
    3  1949   01/01/2018           15        21  01/12/2017
    4  1949   01/01/2018           15        20  01/12/2017
    5  3212   01/01/2018           21        17  31/11/2017
    
  • 1
    cols_to_ffill = ['PropertyType', 'VisitDate']
    i = df.copy()
    
    newdata = pd.DataFrame(['placeholder'] )
    
    while not newdata.index.empty:
    
        RowAboveid = i.id.shift()
        RowAboveRD = i.ReceivedDate.shift()
        rows_with_cols_to_ffill_all_empty = i.loc[:, cols_to_ffill].isnull().all(axis=1)
        rows_to_ffill = (i.ReceivedDate == RowAboveRD) & (i.id == RowAboveid) & (rows_with_cols_to_ffill_all_empty)
        rows_used_to_fill = i[rows_to_ffill].index-1
    
        newdata = i.loc[rows_used_to_fill, cols_to_ffill]
        newdata.index +=1
        i.loc[rows_to_ffill, cols_to_ffill] = newdata
    

    保持循环直到不再匹配(即所有列都向前填充 . )

相关问题