【问题标题】:Using fillna() selectively in pandas在 pandas 中选择性地使用 fillna()
【发布时间】: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 的东西。任何关于实现这一目标的有效方法的建议?

【问题讨论】:

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


    【解决方案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 秒
    猜你喜欢
    • 2019-10-05
    • 1970-01-01
    • 2018-04-26
    • 2017-01-07
    • 2019-10-02
    • 2021-07-06
    • 2021-01-20
    • 2020-10-18
    • 2013-12-28
    相关资源
    最近更新 更多