如何在修改旧值的情况下在 pandas 中使用 `Series.interpolate`

How to use `Series.interpolate` in pandas with the old values modified

pandas 中的 interploate 方法使用有效数据对 nan 值进行插值。但是,它保持旧的有效数据不变,如下代码。

有没有什么方法可以使用 interploate 方法更改旧值,使序列变得平滑?

In [1]: %matplotlib inline
In [2]: from scipy.interpolate import UnivariateSpline as spl
In [3]: import numpy as np
In [4]: import pandas as pd
In [5]: samples = { 0.0: 0.0, 0.4: 0.5, 0.5: 0.9, 0.6: 0.7, 0.8:0.3, 1.0: 1.0 }
In [6]: x, y = zip(*sorted(samples.items()))

In [7]: df1 = pd.DataFrame(index=np.linspace(0, 1, 31), columns=['raw', 'itp'], dtype=float)

In [8]: df1.loc[x] = np.array(y)[:, None]
In [9]: df1['itp'].interpolate('spline', order=3, inplace=True)
In [10]: df1.plot(style={'itp': 'b-', 'raw': 'rs'}, figsize=(8, 6))

In [11]: df2 = pd.DataFrame(index=np.linspace(0, 1, 31), columns=['raw', 'itp'], dtype=float)
In [12]: df2.loc[x, 'raw'] = y
In [13]: f = spl(x, y, k=3)
In [14]: df2['itp'] = f(df2.index)
In [15]: df2.plot(style={'itp': 'b-', 'raw': 'rs'}, figsize=(8, 6))

当您将 Series.interpolatemethod='spline' 一起使用时,在后台 Pandas 使用 interpolate.UnivariateSpline.

返回的样条 UnivariateSpline 不能保证通过作为输入给出的数据点除非 s=0。 但是,默认情况下 s=None,它使用不同的平滑因子,因此会导致不同的结果。

Series.interpolate方法总是填充NaN 值 不改变非 NaN 值。没有办法使 Series.interpolate 修改非 NaN 值。所以,当s != 0时,结果 产生锯齿状跳跃。

所以如果你想要 s=None(默认)样条插值但没有 锯齿状的跳跃,正如您已经发现的,您必须调用 UnivariateSpline 直接覆盖 df['itp']:

中的所有值
df['itp'] = interpolate.UnivariateSpline(x, y, k=3)(df.index)

如果你想要一个通过所有非 NaN 数据点的三次样条,那么 使用 s=0

df['itp'].interpolate('spline', order=3, s=0, inplace=True)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.interpolate as interpolate

samples = { 0.0: 0.0, 0.4: 0.5, 0.5: 0.9, 0.6: 0.7, 0.8:0.3, 1.0: 1.0 }
x, y = zip(*sorted(samples.items()))

fig, ax = plt.subplots(nrows=3, sharex=True)
df1 = pd.DataFrame(index=np.linspace(0, 1, 31), columns=['raw', 'itp'], dtype=float)
df1.loc[x] = np.array(y)[:, None]

df2 = df1.copy()
df3 = df1.copy()

df1['itp'].interpolate('spline', order=3, inplace=True)
df2['itp'] = interpolate.UnivariateSpline(x, y, k=3)(df2.index)
df3['itp'].interpolate('spline', order=3, s=0, inplace=True)
for i, df in enumerate((df1, df2, df3)):
    df.plot(style={'itp': 'b-', 'raw': 'rs'}, figsize=(8, 6), ax=ax[i])
plt.show()