【问题标题】:Pandas.DataFrame interpolate() with method='linear' and 'nearest' returns inconsistent results for trailing NaN带有 method='linear' 和 'nearest' 的 Pandas.DataFrame interpolate() 为尾随 NaN 返回不一致的结果
【发布时间】:2021-10-25 16:51:17
【问题描述】:

我正在使用不同的方法探索pandas.DataFrame.interpolate()linearnearest,当尾随缺少数据时,我发现这两种方法的输出不同。

例如:

import pandas as pd # version: '0.16.2' or '0.20.3'
>>> a = pd.DataFrame({'col1': [np.nan, 1, np.nan, 3, np.nan, 5, np.nan]})
Out[1]: 
   col1
0   NaN
1   1.0
2   NaN
3   3.0
4   NaN
5   5.0
6   NaN

>>> a.interpolate(method='linear')
Out[2]: 
   col1
0   NaN
1   1.0
2   2.0
3   3.0
4   4.0
5   5.0
6   5.0

>>> a.interpolate(method='nearest')
Out[3]: 
   col1
0   NaN
1   1.0
2   1.0
3   3.0
4   3.0
5   5.0
6   NaN

似乎linear 方法会对尾随的 NaN 进行外推,而“最近”方法则不会,除非您指定 fill_value = 'extrapolate'

>>> a.interpolate(method='nearest', fill_value='extrapolate')
Out[4]: 
   col1
0   NaN
1   1.0
2   1.0
3   3.0
4   3.0
5   5.0
6   5.0

所以我的问题是为什么这两种方法在处理尾随 NaN 时表现不同?这是它应该是什么还是一个错误?

在“0.16.2”和“0.20.3”这两个版本的 pandas 中发现了相同的结果。

pandas.Series.interpolate() 也出现了同样的问题。

有一个thread 和一个github issue 在谈论类似的问题,但目的不同。我正在寻找这个问题的解释或结论。

编辑:

更正:linear 方法的行为方式与extrapolation 不完全相同,您可以看到最后一行的填充值是 5 而不是 6。现在看起来更像是一个错误,是吗?

【问题讨论】:

    标签: python pandas interpolation


    【解决方案1】:

    @D.Weis 这是一个很好的问题,让我深入解释一下,没有线程和 github 问题。让我一步一步解释。

    >>> a = pd.DataFrame({'col1': [np.nan, 1, np.nan, 3, np.nan, 5, np.nan]})
    Out[1]: 
       col1
    0   NaN
    1   1.0
    2   NaN
    3   3.0
    4   NaN
    5   5.0
    6   NaN
    

    1.)“线性”插值

    在“线性”插值中,缺失值由两个最近的位置值填充。在“最近”插值中,它将用最近的周围值填充缺失值,但是,在“最近”中,缺失值将与附近位置值具有相同的值。我在第 (2) 节中更深入地解释了“最近”插值。

    用于“线性”插值的 Emaple:

        1   1.0    1. 1.0 
        2   NaN    2. 2.0
        3   3.0    3. 3.0
        4   NaN    4. 4.0
    

    这里,第二个位置是空的。因此,要填充它的值,它将采用位置 1st 和 3rd 的值,分别为 1.0 和 3.0。再次记住,在“线性”插值中,只需 2 个周围的值即可填充缺失值。

    (1.0+3.0/2) =2.0 = Answer for  2nd position. Similarly it will be for other values.
    

    2.) 按“最近”插值

    >>> a.interpolate(method='nearest')
    Out[3]: 
       col1
    0   NaN
    1   1.0
    2   1.0
    3   3.0
    4   3.0
    5   5.0
    6   NaN
    

    基本上,在“最近”插值中,它用最接近值的相同值填充缺失值。例如,

    1   1.0    1. 1.0 
    2   NaN    2. 1.0
    3   3.0    3. 3.0
    4   NaN    4. 3.0
    

    因此,在上面的示例中,您可以很容易地看到位置 2nd 与位置 1st 具有相同的值,因为它是最接近第 1 位置的值。总之,请记住,在“最近”插值中,缺失值在最近的周围值的帮助下被相同的值填充。

    method='nearest', fill_value='extrapolate' 中,您可以在您的示例中看到它将用第五个位置的相同值填充最后一个值。这个概念与上面解释的填充缺失值的概念相同。

    注意: 此外,还有其他的插值方法,如'bilinear'、'bicubic'等,都是为了填补缺失值的准确性。

    我的建议是,如果您想从“最近”和“线性”插值中进行选择。我会说使用“线性”插值,因为它会比“最近”插值更准确地填充值。

    希望这会对您有所帮助。祝你好运!

    【讨论】:

    • 感谢对两种插值方法概念的解释。但是 OP 中的问题是,为什么熊猫的两种插值方法对尾随缺失数据的处理方式不同,此外,为什么“线性”插值的输出似乎不正确。
    • @D. Weis 因为尾部没有第二个相邻值,所以它会采用与上面相同的值。
    【解决方案2】:

    默认情况下,df.interpolate(method='linear') 在最后一个有效值之后向前填充 NaN。考虑到方法名称只提到“插值”,这相当令人惊讶。

    要限制 df.interpolate 仅在有效(非 NaN)值之间插入 NaN, 从 Pandas 版本 0.23.0 (Reference) 开始,使用 limit_area='inside'

    import pandas as pd
    import numpy as np
    a = pd.DataFrame({'col1': [np.nan, 1, np.nan, 3, np.nan, 5, np.nan]})
    a['linear'] = a.interpolate(method='linear')['col1']
    a['linear inside'] = a.interpolate(method='linear', limit_area='inside')['col1']
    print(a)
    

    产量

       col1  linear  linear inside
    0   NaN     NaN            NaN
    1   1.0     1.0            1.0
    2   NaN     2.0            2.0
    3   3.0     3.0            3.0
    4   NaN     4.0            4.0
    5   5.0     5.0            5.0
    6   NaN     5.0            NaN
    

    【讨论】:

    • 感谢您的澄清。 @jreback 也指向了相同的方向。但我只是尝试使用 pandas 0.22.0 但仍然没有看到预期的结果。有任何想法吗?谢谢! a['linear inside'].values: [ nan, 1., 2., 3., 4., 5., 5.]
    • 如果上面的代码在 pandas 0.22.0 上产生了这个结果,那么这是一个错误。但是,如果您要提交错误报告,开发人员会要求您做的第一件事就是升级到最新版本。 FWIW,limit_area 似乎在 pandas 0.24.0 上按预期工作。
    • 是的,pandas 0.24.0 给出了您的示例中的预期结果。再次感谢您的帮助! pandas 0.22.0 中的 limit_area 似乎没有按应有的方式运行。
    • 已确认。 limit_area 在 pandas 0.23.0+ 中按预期工作,但在 0.21.0 或 0.22.0 中没有。 github commit 也表示 0.23.0+。所以也许熊猫document需要更新?
    猜你喜欢
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 2017-03-16
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多