在 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()的主要内容,如果未能解决你的问题,请参考以下文章

使用 fillna 在 Pandas 中使用列表填充空值

pandas使用fillna函数对dataframe中不同的数据列使用不同的方式内容进行填充

在 Pandas 中具有向后和向前看状态的 Fillna

如何在 pandas fillna() 方法中为不同的列应用不同的方法参数

Fillna 一次使用多种方法 - pandas

pandas使用fillna函数将dataframe中缺失值替换为空字符串(replace missing value with blank string in dataframe)