在 Pandas 中跨稀疏网格进行插值

问题描述

我有一个数字网格(选项波动率,见下图),其中网格末端的条目很少(即非常稀疏)。我想通过使用整个网格的数据来插入\填充这个网格,即二维插值方法。我看过一些例子(例如 here),但我不熟悉 scipy 和 numpy API,而且似乎他们正在做一堆与实际插值无关的图形。

明确地说,我目前将此数据存储在一个带有索引 OPT_EXPIRE_DTOPT_STRIKE_PX 的 Pandas 数据帧中,并且希望在最后得到另一个 Pandas 数据帧,但我可以转换根据需要转换为其他数据类型。

感谢您的帮助!

grid data

解决方法

这是一个例子。让我们先创建一些缺失值的 DataFrame:

N = 5
df = pd.DataFrame(np.empty((N,N)))
df.iloc[:] = np.nan
df.iloc[:2] = 1
df.iloc[-2:] = 2
df

输出:

     0    1    2    3    4
0  1.0  1.0  1.0  1.0  1.0
1  NaN  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN  NaN
3  NaN  NaN  NaN  NaN  NaN
4  2.0  2.0  2.0  2.0  2.0

然后我们可以使用 griddata 进行插值:

# create meshgrid
x,y = np.mgrid[0:N,0:N]

# find indices of non-missing values
ix_notna = df.notna().values

# interpolate
z_interpolated = interpolate.griddata(
    (x[ix_notna],y[ix_notna]),df.values[ix_notna],(x,y),method='linear')

# griddata returns numpy array,so we convert it back to DataFrame
df_interpolated = pd.DataFrame(z_interpolated)
df_interpolated

输出:

      0     1     2     3     4
0  1.00  1.00  1.00  1.00  1.00
1  1.25  1.25  1.25  1.25  1.25
2  1.50  1.50  1.50  1.50  1.50
3  1.75  1.75  1.75  1.75  1.75
4  2.00  2.00  2.00  2.00  2.00

我们可以直观地检查它是否按预期工作:

fig,ax = plt.subplots(1,2)
ax[0].imshow(df.values)
ax[0].set_title('original')
ax[1].imshow(df_interpolated.values)
ax[1].set_title('interpolated')

输出:

image

,

所以,我认为您想要做的是转换为一个 numpy 数组并返回,这应该相当简单。这是通过线性插值计算简单数组的 NaN 条目值的代码。输出数组变为 np.array([[1,2,3],[2,3,4],[5,5.5,6]]).

from scipy.interpolate import interp2d
import numpy as np

# simple 2d array to interpolate
d = np.array([[1,float('NaN')],[float('NaN'),float('NaN'),6]])

# finds indices where values aren't NaN
valsX,valxY = np.where(np.isnan(d)==False)

# creates interpolation function from values that aren't NaN
interp = interp2d(valsX,valsY,d[valsX,valsY])

# copies original array in case you want to use it
dprime = np.copy(d)

# indices that are NaN we need to change
nanX,nanY = np.where(np.isnan(d))

# runs through all points with interpolation function
for i in range(len(nanX)):
    dprime[nanX[i],nanY[i]] = interp(nanX[i],nanY[i])