首页 > 解决方案 > 如何使用 scipy 的插值程序用 NaN 插值数据?

问题描述

我有一些需要插值的二维数据数组。SciPy对此提供了一些解决方案,例如在这里很好地解释了。我的数据非常粗略地看起来像一个 2D 抛物线(作为 x1 和 x2 的函数),开口朝下,如图 1 所示,沿 x2=0 进行水平切割。如您所见,没有负值(那里的数据点都正好是 0)。

图 1:示例数据集沿 x2=0 的水平切割

我想执行三次插值,因为我需要平滑的数据。这会在边缘出现问题,导致拟合/插值的“摆动”或“过冲”,如图 2 所示。但是,在插值数据的后续后处理中不允许使用负值(也需要抑制以下过冲到应该为零的正值)。

图 2:示例数据集沿 x2=0 的水平切割和插值; 可以清楚地看到边缘的过冲.

我认为一个聪明的“解决方案”是简单地将 0 的值(请注意,它们都完全相同)设置为NaN,这样它们就会被插值忽略。但是使用SciPy'sgriddata并且该cubic方法不适用于NaNs。该linear方法可以处理此问题,但我需要cubic.

我的问题是,我是否遗漏了什么或做错了什么导致s 和方法griddata无法正常工作?NaNcubic

示例代码如下:

import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate as interp

def some_funct( x1, x2 ):
    result = -x1**2 - 2.*x2**2 + 60.
    result[result < .0] = .0
    return result

# define original (sparse) grid
N_x1, N_x2     = 20, 20
x1_old         = np.linspace( -9, 10, N_x1 )
x2_old         = np.linspace( -9, 10, N_x2 )
X1_old, X2_old = np.meshgrid( x1_old, x2_old )

# datapoints to be interpolated
z_old = some_funct( X1_old, X2_old )

# set 0 datapoints to nan
z_old[z_old==0] = np.nan

# grid for interpolation
x1_new         = np.linspace( -9, 10, 10*N_x1 )
x2_new         = np.linspace( -9, 10, 10*N_x2 )
X1_new, X2_new = np.meshgrid( x1_new, x2_new )

# perform interpolation
z_new = interp.griddata( np.array([X1_old.ravel(),X2_old.ravel()]).T, z_old.ravel(),
                         (X1_new, X2_new), 
                         method='cubic', fill_value=.0  # only works for 'linear'
                       )

# plot horizonal cut along x2=0
fig1 = plt.figure( figsize=(8,6) )
ax1  = fig1.add_subplot( 1,1,1 )
x2_old_0_id = (np.abs(x2_old - .0)).argmin()
x2_new_0_id = (np.abs(x2_new - .0)).argmin()
ax1.plot( x1_old, z_old[ x2_old_0_id , : ], marker='x', linestyle='None', label='data' )
ax1.plot( x1_new, z_new[ x2_new_0_id , : ], label='interpolation' )
ax1.legend()
ax1.set_xlabel( 'x1' )
ax1.set_ylabel( 'z' )
plt.show()

非常感谢任何提示!

更新:忘记包含我正在使用的版本:

numpy: 1.15.1
scipy: 1.1.0

标签: pythonscipyinterpolation

解决方案


对于不超调的单调三次插值,使用pchipAkima1DInterpolator


推荐阅读