为了账号安全,请及时绑定邮箱和手机立即绑定

结合 bfill() 和 ffill() 功能

结合 bfill() 和 ffill() 功能

皈依舞 2021-09-14 21:05:12
说我有以下几点pd.Series:0     NaN1     NaN2     4.03     NaN4     NaN5     7.06     NaN7     NaN8     NaN9     NaN10    1.011    NaN12    NaN13    6.014    NaN15    NaN我试图获得一个系列,其中NaNs由周围的有效样本同样填充。所以说我有N NaNs两个有效样本,我希望第一个N/2 NaNs由最后一个有效样本填充,最后一个N/2 NaNs由下一个有效观察填充。在这种情况下(N % 2) =! 0,额外的观察可以由两个周围的任何一个填充,适用的规则是可以的。所以我想获得:0     41     42     43     44     75     76     77     78     19     110    111    112    613    614    615    6
查看完整描述

3 回答

?
慕妹3146593

TA贡献1820条经验 获得超9个赞

想法是创建布尔面具和过滤bfill用where,然后ffill和最后bfill仅如果通过启动第一系列的第一个值再次NaN:


m = df['A'].notna()

c = m.cumsum()


def f(x):

    lens = len(x.index)

    a = np.arange(lens)

    return a // (lens / 2) == 0


mask = c[~m].groupby(c).transform(f)

#should be removed

#mask = mask.reindex(df.index, fill_value=False)

df['B'] = df['A'].where(mask, df['A'].bfill()).ffill().bfill()

print (df)

      A    B

0   NaN  4.0

1   NaN  4.0

2   4.0  4.0

3   NaN  4.0

4   NaN  7.0

5   7.0  7.0

6   NaN  7.0

7   NaN  7.0

8   NaN  1.0

9   NaN  1.0

10  1.0  1.0

11  NaN  1.0

12  NaN  6.0

13  6.0  6.0

14  NaN  6.0

15  NaN  6.0


查看完整回答
反对 回复 2021-09-14
?
HUWWW

TA贡献1874条经验 获得超12个赞

import pandas as pd

while pd.isnull(my_series).sum() > 0:

    my_series = my_series.fillna(method='ffill', limit=1).fillna(method='bfill', limit=1)

说这会很慢可能是轻描淡写。如果您想在大型 DataFrame 上执行此操作,我可能会尝试使用我可以使用的函数来实现它apply。


我从来没有真正想出这样做的好主意(但我一直在关注这个问题,因为这是一个有趣的问题)。我喜欢另一个聪明的答案,但我很好奇它在速度方面的表现。


def funcA(pd_series):

    m = pd_series.notna()

    c = m.cumsum()

    def f(x):

        lens = len(x.index)

        a = np.arange(lens)

        return a // (lens / 2) == 0

    mask = c[~m].groupby(c).transform(f)

    #should be removed

    #mask = mask.reindex(df.index, fill_value=False)

    return pd_series.where(mask, pd_series.bfill()).ffill().bfill()


def funcB(pd_series):

    while pd.isnull(pd_series).sum() > 0:

        pd_series = pd_series.fillna(method='ffill', limit=1).fillna(method='bfill', limit=1)

    return pd_series


ps = pd.Series(np.random.randint(0,10, size=(10000)))

ps[ps < 5] = np.nan


>>> import timeit

>>> timeit.timeit('funcA(ps)', setup='from __main__ import funcA, ps', number=100)

40.9788393480012

>>> timeit.timeit('funcB(ps)', setup='from __main__ import funcB, ps', number=100)

0.4896140840010048

嗯......这并不像我期望的那么好。带有半 NaN 的小型系列可能不是一个很好的测试,所以也许尝试一些 while 循环应该阻塞的东西?


ps = pd.Series(np.random.randint(0,100, size=(1000000)))

ps[ps < 95] = np.nan


>>> timeit.timeit('funcA(ps)', setup='from __main__ import funcA, ps', number=10)

81.64654629600045

>>> timeit.timeit('funcB(ps)', setup='from __main__ import funcB, ps', number=10)

21.431495654000173

嗯,那至少更接近了。我懒得再扩大规模了,但看起来你可能需要 10^7 个条目和 95%+ NaN 之前屏蔽和安排的额外开销得到回报。


查看完整回答
反对 回复 2021-09-14
  • 3 回答
  • 0 关注
  • 501 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号