在 pandas 中选择性地使用 fillna()
Posted
技术标签:
【中文标题】在 pandas 中选择性地使用 fillna()【英文标题】:Using fillna() selectively in pandas 【发布时间】:2017-03-19 10:40:26 【问题描述】:我想以选择性的方式在 DataFrame 中填充 N/A 值。特别是,如果一列中有一系列连续的 nan,我希望它们被前面的非 nan 值填充,但前提是 nan 序列的长度低于指定的阈值。例如,如果阈值为 3,则 3 或更少的列内序列将填充前面的非 nan 值,而 4 或更多 nan 的序列将保持原样。
也就是说,如果输入的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 个 nan,而不是如上所述的选择性。
我想这可以通过使用一些条件语句逐列进行编码,但我怀疑肯定有一些更 Pythonic 的东西。任何关于实现这一目标的有效方法的建议?
【问题讨论】:
【参考方案1】:在 pandas 中与连续组一起工作仍然有点尴尬。或者至少我不知道有什么巧妙的方法可以做到这一点,这根本不是一回事。 :-)
获得所需内容的一种方法是使用 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 的元素。
【讨论】:
谢谢@DSM。这是一个非常好的解决方案,它确实为我们提供了我们正在寻找的东西。只有一条评论:它很慢。我对大小为 530x11500 的 DataFrame 使用了 3 的限制,大约需要 32 秒。因此,尽管此解决方案很棒,但我们将高度赞赏降低所涉及的运行时间的替代解决方案 确实快得多!挂起时间:9.01 秒以上是关于在 pandas 中选择性地使用 fillna()的主要内容,如果未能解决你的问题,请参考以下文章
pandas使用fillna函数对dataframe中不同的数据列使用不同的方式内容进行填充
如何在 pandas fillna() 方法中为不同的列应用不同的方法参数
pandas使用fillna函数将dataframe中缺失值替换为空字符串(replace missing value with blank string in dataframe)