假设我们有一个数组a = np.array([1,2,0,4,0,5,0,0,11])
,我们如何得到:
array([ 1, 2, 3, 4, 4.5, 5, 7, 9, 11])
我试过的是:
from scipy.interpolate import interp1d
a = np.array([1,2,0,4,0,5,0,0,11])
b = a[np.nonzero(a)]
brange = np.arange(b.shape[0])
interp = interp1d(brange, b)
这似乎是找到中间值的实际工作。例如:
print (interp(1), interp(1.5), interp(2), interp(2.5), interp(3))
#out: 2.0 3.0 4.0 4.5 5.0
但我无法弄清楚如何从interp
重新构建原始数组。我也尝试了this question的解决方案,但我也遇到了与该解决方案完全相同的问题。
更新
我使用numpy和pandas为这两个解决方案做了快速基准测试,结果如下:
y = np.array([1,2,0,4,0,5,0,0,11])
def test1(y):
x = np.arange(len(y))
idx = np.nonzero(y)
interp = interp1d(x[idx],y[idx])
return interp(x)
def test2(y):
s = pd.Series(y)
s.interpolate(inplace=True)
return s.values
%timeit t1 = test1(y)
%timeit t2 = test2(y)
139 µs ± 1.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
158 µs ± 2.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
快12%左右。不如我希望的那么好,但由于代码将运行数百万次,所以可能值得付出努力。
答案 0 :(得分:3)
你需要提供interp1d
一个y-array 而不用零和一个跳过所述零的x数组。然后,对于插值,您必须为插值函数提供一个x数组,该数组包含所有原始x值以及您希望插值发生的值。在您的情况下,由于您有一个准备好的等距矢量,您可以使用np.arange
生成x值,使用np.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)
结果如下:
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. ]
修改强>:
实际上你不需要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)
答案 1 :(得分:2)
我认为您的实施有点偏差。你想要的是更接近@Thomas想出的东西:
y = np.array([1,2,0,4,0,5,0,0,11])
idx = np.nonzero(y)
interp = interp1d(x[idx],y[idx])
x = np.arange(len(y))
ynew = interp(x)
如果您想从interp
重新构建原始数组,只需使用.x
和.y
参数。
a_ = np.zeros(interp.x[-1] + 1)
a_[interp.x] = interp.y
当然,这会从原始a
中删除任何尾随零,因为a.size
未在插值中保留。如果您已将其保留在其他位置(例如ynew.shape
),则可以改为初始化a_ = np.zeros_like(ynew)
答案 2 :(得分:1)
您可以使用pandas
interpolate
功能:
import pandas as pd
import numpy as np
a = pd.Series([1,2,0,4,0,5,0,0,11])
a.replace(0, np.NaN, inplace=True)
a.interpolate()
0 1.0
1 2.0
2 3.0
3 4.0
4 4.5
5 5.0
6 7.0
7 9.0
8 11.0
另外:a.interpolate().values
会为您提供一系列值。
# output: array([ 1. , 2. , 3. , 4. , 4.5, 5. , 7. , 9. , 11. ])
另外:interpolate
将inplace
作为参数,您可以使用