Python 在长间隙内插值并替换为NaN?

Python 在长间隙内插值并替换为NaN?,python,interpolation,Python,Interpolation,我试图用间隙来插值数据。有时差距可能很大,我不希望插值在差距内“成功”;结果应该是NaNs在一个大间隙内。例如,考虑这个示例数据集: orig_x=[262192622526232852128538] 原始y=[39,40,41,72,71] 在x值26232和28521之间有明显的差距。现在,我想将orig_y插值为x值,如下所示: 将numpy导入为np x_target=np.array(范围(最小(原点x)//10*10+10,最大(原点x)//10*10+10,10)) #阵列([2

我试图用间隙来插值数据。有时差距可能很大,我不希望插值在差距内“成功”;结果应该是
NaN
s在一个大间隙内。例如,考虑这个示例数据集:

orig_x=[262192622526232852128538]
原始y=[39,40,41,72,71]
在x值26232和28521之间有明显的差距。现在,我想将
orig_y
插值为x值,如下所示:

将numpy导入为np
x_target=np.array(范围(最小(原点x)//10*10+10,最大(原点x)//10*10+10,10))
#阵列([2622026230262402625026260262702628026290,
#        ...
#       28460, 28470, 28480, 28490, 28500, 28510, 28520, 28530])
并且输出
y_目标
应该是
np.nan
,而不是
26220
26230
28520
。假设这样做的条件是,如果数据中存在大于
40
的间隙,则插值应导致该数据间隙内出现
np.nan

如图所示的目标 而不是这个

得到像这样的东西

i、 e.数据中的“间隙”应导致
np.nan
,而不是垃圾数据

问题: 实现这种插值的最佳方式(最快插值)是什么?插值可以是线性的或更复杂的(例如三次样条曲线)。我想到的一种可能性是,使用

从scipy.interpolate导入interp1d
f=interp1d(原点x,原点y,边界错误=False)
y_目标=f(x_目标)

然后搜索数据中的间隙,并将插值数据替换为间隙内的
np.nan
。由于我将在相当大的数据集(大约10万行,几列,分部分处理)上使用它,所以性能是一个关键。

经过一些尝试和错误后,我认为我得到了一个“足够快”的实现,使用basic和for speedups。请原谅在同一个循环和同一个函数中编写所有内容,但这似乎是加快代码速度的一种方法。(numba喜欢循环,似乎不接受嵌套函数)

使用的测试数据 我在
x_target
中添加了一些模式数据来测试算法性能

orig_x = np.array([26219, 26225, 26232, 28521, 28538])
orig_y = np.array([39, 40, 41, 72, 71])

x_target = np.array(
    np.arange(min(orig_x) // 10 * 10,
              max(orig_x) // 10 * 10 + 10, 0.1))
测试代码 测试结果 在间隙小于
max_gap
(40)的区域内插入数据:

特写:

速度
我首先尝试了一个纯python+numpy实现,使用相同的测试数据(使用
timeit
)需要49.6毫秒。使用numba实现此功能需要480µs(加速100倍!)。使用
目标时,速度为80.1µs

orig_x_sorted=True
没有放弃加速,可能是因为
orig_x
很短,所以在本例中排序不会对计时产生任何影响

实施
导入numba
将numpy作为np导入
@numba.njit()
def用_max_间隙(原点x)插值_,
最初,
目标(x),
最大间隙=np.inf,
orig_x_is_sorted=False,
目标_x_为_排序=假):
"""
以最大间距线性插值数据。如果存在
数据缺口大于“最大缺口”,缺口将被填补
与np.nan。
输入值不应包含NAN。
参数
---------
orig_x:np.array
输入x-数据
源:np.array
输入y数据
target_x:np.array
输出x数据;x轴上的数据点
您希望插值结果来自。
最大间隙:浮动
“orig_x”中的最大允许间隙,其中
仍在执行插值。间隙大于
这将在输出“target_y”中填入np.nan。
orig_x_排序:布尔,默认值:False
如果为True,则假定输入数据“orig_x”是单调的
增加。如果提供已排序的输入数据,则会获得一些性能增益。
目标_x_排序:布尔,默认值:False
如果为True,则假定输入数据'target_x'为
单调递增。如果您提供
已排序的输入数据。
退换商品
------
目标_y:np.array
插值结果。
"""
如果不是原始的,则对x进行排序:
#有点单调。输入x变量。
idx=orig_x.argsort()
orig_x=orig_x[idx]
原点y=原点y[idx]
如果不是目标\u x\u已\u排序:
target_idx=target_x.argsort()
#需要对数据进行排序。
target\u idx\u for\u reverse=target\u idx.argsort()
target_x=target_x[target_idx]
target_y=np.empty(target_x.size)
idx_orig=0
原始通过=错误
对于idx_目标,枚举中的新x_(目标):
#如果需要,增加idx_orig。
虽然不是最初的经历:
如果idx_orig+1>=len(orig_x):
#已经消耗了orig_x;没有更多的数据
#所以我们需要推断
最初的经历=正确
elif x_new>orig_x[idx_orig+1]:
idx_orig+=1
其他:
#x_新的最大间隙:
target_y[idx_target]=np.nan
持续
δy=y2-y1
如果delta_x==0:
target_y[idx_target]=np.nan
持续
k=δy/δx
delta_x_new=x_new-x1
delta_y_new=k*delta_x_new
y_新=y1+增量y_新
target_y[idx_target]=y_new
如果不是目标\u x\u已\u排序:
返回target_y[target_idx_for_reverse]
返回目标

有趣的问题。把这张图变成虚线而不是实线是否适合你?也许你的数据看到的不止n个
from matplotlib import pyplot as plt

y_target = interpolate_with_max_gap(orig_x, orig_y, x_target, max_gap=40)

plt.scatter(x_target, y_target, label='interpolated', s=10)
plt.scatter(orig_x, orig_y, label='orig', s=10)
plt.legend()
plt.show()