如何编写返回内插值的函数(Pandas DataFrame)?

2022-04-04 00:00:00 python pandas interpolation

问题描述

我有一个作为 pandas 数据帧导入的XLS文件。它有NaN值;我如何设置一个函数,用相邻值之间的插值法替换NaN?我不能使用pd.DataFrame.interpolate或任何现有的内插函数,因为我应该创建自己的函数。

这是我所拥有的,但我认为这是非常错误的。抱歉,对Python来说还很陌生:(

import pandas as pd
file = pd.read_excel("xls file")

def interpolate(x):
  for i in range(len(x)):
    if x.iloc[i, -1].isnull():
      x.iloc[i,-1] = (((x.iloc[i-1, -1]) + (x.iloc[i+1, -1]))/2)
    else:
      x.iloc[i,-1] = x.iloc[i, -1]

interpolate(file)

例如,数据帧最初看起来如下所示:

0   1.04
1   0.99
2   NaN
3   1.05
4   1.05

我希望它返回:

0   1.04
1   0.99
2   1.02
3   1.05
4   1.05

为此,假设没有连续的NaN条目


解决方案

此解决方案使用默认参数重新创建pd.Series.interpolate的行为。这不是一个适合初学者的解决方案,如果你的问题是家庭作业,我很好奇你的教授会期待什么。

我使用的数据帧具有前导、尾随和连续的nan值。我添加了一个带有插值值的列,以与我的解决方案进行比较。需要具有默认排序范围索引的Series

import pandas as pd
import numpy as np

np.random.seed(11)
a = np.where(np.random.rand(20) > .5, np.random.uniform(0,10, 20), np.nan)
df = pd.DataFrame({
    'x': a
})
df['x_interp'] = df.x.interpolate()
df

输出

           x  x_interp
0        NaN       NaN
1        NaN       NaN
2        NaN       NaN
3   3.187988  3.187988
4        NaN  2.661738
5        NaN  2.135487
6        NaN  1.609237
7        NaN  1.082987
8   0.556737  0.556737
9   4.797973  4.797973
10  4.016765  4.016765
11       NaN  5.597628
12  7.178492  7.178492
13  6.020641  6.020641
14       NaN  7.755832
15  9.491024  9.491024
16       NaN  9.491024
17       NaN  9.491024
18       NaN  9.491024
19       NaN  9.491024

方法是使用nan和周围的值查找切片。然后在周围的值之间用线性步长填充这些切片。ffill参数控制尾部nan是否将用最后一个可用值填充。

def interp(ser, ffill=True):
    ser = ser[df.x.notna().idxmax():].copy()
    start = ser.notna() & ser.shift(-1, fill_value=0).isna()
    end = ser.notna() & ser.shift(1, fill_value=0).isna()
    
    for x,y in zip(ser.index[start],ser.index[end]):
        step = (ser.loc[y] - ser.loc[x])/(y - x)
        ser.loc[x:y] = [ser.loc[x] + i * step for i in range(y-x)] + [ser.loc[y]]

    if ffill:
        ser = ser.ffill()
        
    return ser

df['x_new_interp'] = interp(df.x, False)
df['x_new_interp_ffill'] = interp(df.x)
df

输出

           x  x_interp  x_new_interp  x_new_interp_ffill
0        NaN       NaN           NaN                 NaN
1        NaN       NaN           NaN                 NaN
2        NaN       NaN           NaN                 NaN
3   3.187988  3.187988      3.187988            3.187988
4        NaN  2.661738      2.661738            2.661738
5        NaN  2.135487      2.135487            2.135487
6        NaN  1.609237      1.609237            1.609237
7        NaN  1.082987      1.082987            1.082987
8   0.556737  0.556737      0.556737            0.556737
9   4.797973  4.797973      4.797973            4.797973
10  4.016765  4.016765      4.016765            4.016765
11       NaN  5.597628      5.597628            5.597628
12  7.178492  7.178492      7.178492            7.178492
13  6.020641  6.020641      6.020641            6.020641
14       NaN  7.755832      7.755832            7.755832
15  9.491024  9.491024      9.491024            9.491024
16       NaN  9.491024           NaN            9.491024
17       NaN  9.491024           NaN            9.491024
18       NaN  9.491024           NaN            9.491024
19       NaN  9.491024           NaN            9.491024

相关文章