【问题标题】:Fill nan gaps in pandas df only if gaps smaller than N nans仅当间隙小于 N nans 时才填充 pandas df 中的 nan 间隙
【发布时间】:2021-11-08 06:57:12
【问题描述】:

我正在使用一个也包含 nan 值的 pandas 数据框。我想用 df.interpolate 的插值替换 nans,但前提是 nan 值序列的长度为 =的数据框

print(df)
A   B   C
1   1   1
nan nan 2
nan nan 3
nan 4   nan
5   5   5

在这种情况下,我想在df 上应用一个函数,只填充长度为 N

print(df)
A   B   C
1   1   1
nan 2   2
nan 3   3
nan 4   4
5   5   5

请注意,我知道limit=Ndf.interpolate 中的选项,但它不能满足我的要求,因为它会填充任何长度的 nan 序列,只需将填充限制为前 3 个 nan导致不想要的输出

print(df)
A   B   C
1   1   1
2   2   2
3   3   3
nan 4   4
5   5   5

那么你知道一个函数/你知道如何构造一个产生我想要的输出的代码吗?天呐

【问题讨论】:

  • 您不需要任何应用方法。只需找到符合您条件的列名,然后使用df[cols] = df[cols].interpolate() 插入并覆盖它们。检查我的 2 班轮以供参考。

标签: python pandas dataframe interpolation nan


【解决方案1】:

试试:

N = 2
df_interpolated = df.interpolate()

for c in df:
    mask = df[c].isna()
    x = (
        mask.groupby((mask != mask.shift()).cumsum()).transform(
            lambda x: len(x) > N
        )
        * mask
    )
    df_interpolated[c] = df_interpolated.loc[~x, c]

print(df_interpolated)

打印:

     A    B    C
0  1.0  1.0  1.0
1  NaN  2.0  2.0
2  NaN  3.0  3.0
3  NaN  4.0  4.0
4  5.0  5.0  5.0

尝试不同的df

     A    B    C
0  1.0  1.0  1.0
1  NaN  NaN  2.0
2  NaN  NaN  3.0
3  NaN  4.0  NaN
4  5.0  5.0  5.0
5  NaN  5.0  NaN
6  NaN  5.0  NaN
7  8.0  5.0  NaN

产生:

     A    B    C
0  1.0  1.0  1.0
1  NaN  2.0  2.0
2  NaN  3.0  3.0
3  NaN  4.0  4.0
4  5.0  5.0  5.0
5  6.0  5.0  NaN
6  7.0  5.0  NaN
7  8.0  5.0  NaN

【讨论】:

    【解决方案2】:

    你可以试试下面的-

    n=2
    cols = df.columns[df.isna().sum()<=n]
    df[cols]  = df[cols].interpolate()
    df
    
         A    B    C
    0  1.0  1.0  1.0
    1  NaN  2.0  2.0
    2  NaN  3.0  3.0
    3  NaN  4.0  4.0
    4  5.0  5.0  5.0
    

    df.columns[df.isna().sum()&lt;=n] 根据您的条件过滤列。然后,您只需在插值后覆盖列。

    【讨论】:

    • 谢谢!但是我实际的df 与我作为示例展示的虚拟对象不同 - 真正的df 的长度约为 130 000 行,每列包含不同长度的 nan 序列,有些比 N=2 长,有些比 N=2 短。而且我希望在所有列中填充最多 N 长的序列,所以你的答案不会这样做。不过还是谢谢:)
    【解决方案3】:

    您可以执行游程长度编码并识别每列短于或等于两个元素的 NaN 的游程。一种方法是使用包pdrle 中的get_id(免责声明:我写的)。

    import pdrle
    
    
    chk = df.isna() & (df.apply(lambda x: x.groupby(pdrle.get_id(x)).transform(len)) <= 2)
    df[chk] = df.interpolate()[chk]
    #      A    B    C
    # 0  1.0  1.0  1.0
    # 1  NaN  2.0  2.0
    # 2  NaN  3.0  3.0
    # 3  NaN  4.0  4.0
    # 4  5.0  5.0  5.0
    

    【讨论】:

    • 太棒了,我喜欢它的短,而且它没有在 for 循环中使用显式迭代。但是,您能用 1-2 句话简单介绍一下 pdrle 包,并在一行代码 chk = .... 中发生了什么吗?之后我可以接受这个作为我问题的答案:) 谢谢
    • 此外,代码运行速度很慢 - 我的 10 列中的 130000 行运行时间约为 10 分钟。我认为这是由于.groupby。您认为有一种方法可以加快代码速度吗? tnx
    • @NeStack,我更新了答案。至于加速,cythonnumba 可能是要走的路。
    • cythonnumba 会影响应用于数据帧的 .groupby 函数吗?你能举例说明这个修正案应该是什么样子吗?
    • @NeStack,我正在调查。我会在这里更新并在我弄清楚时标记你。
    猜你喜欢
    • 2015-02-28
    • 2022-01-24
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    相关资源
    最近更新 更多