我想以选择性方式填充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。是否有任何建议以有效的方式实现这一目标?
答案 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的组。