假设我们有一个数组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
重建我的原始数组。我也尝试了这个问题的解决方案,但我对该解决方案也有完全相同的问题。
更新:
我使用 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%。没有我希望的那么好,但由于代码将运行数百万次,因此可能值得付出努力。
你需要interp1d
馈送一个没有零的 y 数组和一个跳过所述零的 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)
您可以使用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
作为您可以使用的参数
我认为你的实现有点不对劲。 你想要的是更接近@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)