在pandas中有选择地使用fillna()

时间:2016-11-05 19:24:35

标签: python python-3.x pandas nan missing-data

我想以选择性方式填充DataFrame中的N / A值。特别是,如果列中存在一系列连续的nans,我希望它们由前面的非nan值填充,但仅限于nan序列的长度低于指定的阈值。例如,如果阈值为3,那么3或更少的列内序列将填充前面的非纳米值,而4个或更多个nans的序列将保留原样。

即,如果输入DataFrame是

    2   5   4
    nan nan nan
    nan nan nan
    5   nan nan
    9   3   nan
    7   9   1

我希望输出为:

    2   5   4
    2   5   nan
    2   5   nan
    5   5   nan
    9   3   nan
    7   9   1

fillna函数应用于DataFrame时,具有方法和限制选项。但遗憾的是,这些不足以完成任务。我尝试指定method='ffill'limit=3,但这填补了任何序列的前3个nans,而不是如上所述的选择性。

我想这可以通过一些条件语句逐列进行编码,但我怀疑必须有更多的Pythonic。是否有任何建议以有效的方式实现这一目标?

1 个答案:

答案 0 :(得分:3)

在熊猫中与邻居群体一起工作仍然有点尴尬..或者至少我不知道做这件事的光滑方式,这根本不是同样的事情。 : - )

获得所需内容的一种方法是使用compare-cumsum-groupby模式:

In [68]: nulls = df.isnull()
    ...: groups = (nulls != nulls.shift()).cumsum()
    ...: to_fill = groups.apply(lambda x: x.groupby(x).transform(len) <= 3)
    ...: df.where(~to_fill, df.ffill())
    ...: 
Out[68]: 
     0    1    2
0  2.0  5.0  4.0
1  2.0  5.0  NaN
2  2.0  5.0  NaN
3  5.0  5.0  NaN
4  9.0  3.0  NaN
5  7.0  9.0  1.0

好吧,另一种我不喜欢的选择,因为它太棘手了:

def method_2(df):
    nulls = df.isnull()
    filled = df.ffill(limit=3)
    unfilled = nulls & (~filled.notnull())
    nf = nulls.replace({False: 2.0, True: np.nan})
    do_not_fill = nf.combine_first(unfilled.replace(False, np.nan)).bfill() == 1
    return df.where(do_not_fill, df.ffill())

这不使用任何groupby工具,所以应该更快。请注意,不同的方法是手动(使用班次)确定要填充哪些元素,因为它们是长度为1,2或3的组。