用其前后值之间的线性插值替换 numpy 数组中的零

Alz*_*Alz 3 python benchmarking interpolation numpy scipy

假设我们有一个数组a = np.array([1,2,0,4,0,5,0,0,11]),我们如何得到:

\n\n
array([ 1,  2,  3,  4,  4.5,  5,  7,  9, 11])\n
Run Code Online (Sandbox Code Playgroud)\n\n

我尝试过的是:

\n\n
from scipy.interpolate import interp1d\n\na = np.array([1,2,0,4,0,5,0,0,11])\nb = a[np.nonzero(a)]\nbrange = np.arange(b.shape[0])\ninterp = interp1d(brange, b)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这似乎确实完成了寻找中间值的实际工作。例如:

\n\n
print (interp(1), interp(1.5), interp(2), interp(2.5), interp(3))\n#out: 2.0 3.0 4.0 4.5 5.0\n
Run Code Online (Sandbox Code Playgroud)\n\n

但我不知道如何从interp. 我也尝试了这个问题的解决方案,但该解决方案也遇到了完全相同的问题。

\n\n

更新:

\n\n

我使用 numpy 和 pandas 对这两个解决方案进行了快速基准测试,结果如下:

\n\n
y = np.array([1,2,0,4,0,5,0,0,11])\n\ndef test1(y):\n\n    x = np.arange(len(y))\n    idx = np.nonzero(y)\n    interp = interp1d(x[idx],y[idx])\n\n    return interp(x)\n\ndef test2(y):\n    s = pd.Series(y)\n    s.interpolate(inplace=True)\n    return s.values\n\n%timeit t1 = test1(y)\n%timeit t2 = test2(y)\n\n139 \xc2\xb5s \xc2\xb1 1.62 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000 loops each)\n158 \xc2\xb5s \xc2\xb1 2.01 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

大约快 12%。没有我希望的那么好,但是由于代码将运行数百万次,因此可能值得付出努力。

\n

Tho*_*ühn 5

您需要提供一个不带interp1d零的y 数组和一个跳过所述零的 x 数组。然后,对于插值,您必须为插值函数提供一个 x 数组,其中包含所有原始 x 值以及您希望出现插值的值。在您的情况下,由于您有一个准备好的等距向量,因此您可以用来生成 x 值并过滤掉零。np.arangenp.where

这里是一个示例代码:

import numpy as np
from scipy.interpolate import interp1d

y = np.array([1,2,0,4,0,5,0,0,11])
xnew = np.arange(len(y))

zero_idx = np.where(y==0)
xold = np.delete(xnew,zero_idx)
yold = np.delete(y, zero_idx)

print('before')
print(xold)
print(yold)

f = interp1d(xold,yold)

ynew = f(xnew)

print()
print('after')
print(xnew)
print(ynew)
Run Code Online (Sandbox Code Playgroud)

结果如下:

before
[0 1 3 5 8]
[ 1  2  4  5 11]

after
[0 1 2 3 4 5 6 7 8]
[  1.    2.    3.    4.    4.5   5.    7.    9.   11. ]
Run Code Online (Sandbox Code Playgroud)

编辑

实际上你不需要np.delete,你可以只使用切片:

y = np.array([1,2,0,4,0,5,0,0,11])
x = np.arange(len(y))
idx = np.where(y!=0)        #or np.nonzero(y) -- thanks DanielF
f = interp1d(x[idx],y[idx])
ynew = f(x)
Run Code Online (Sandbox Code Playgroud)