使用python 3.x进行1-D插值

时间:2018-06-11 22:27:27

标签: python-3.x interpolation

我的数据看起来像一个S形图,但相对于垂直线翻转。 enter image description here

但该情节是绘制一维数据而非某种功能的结果。

我的目标是在y值为50%时找到x值。如您所见,当y恰好为50%时,没有数据点。 插值出现在我的脑海里。但我不确定插值是否允许我在y值为50%时找到x值。所以我的问题是1)当y为50%时,你可以使用插值来找到x吗?或者2)你需要将数据拟合到某种函数中吗?

以下是我目前在代码中的内容

import numpy as np
import matplotlib.pyplot as plt


my_x = [4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66]

my_y_raw=np.array([0.99470977497817203, 0.99434995886145172, 0.98974611323163653, 0.961630837657524, 0.99327633558441175, 0.99338952769251909, 0.99428263292577534, 0.98690514212711611, 0.99111667721533181, 0.99149418924880861, 0.99133773062680464, 0.99143506380003499, 0.99151080464011454, 0.99268261743308517, 0.99289757252812316, 0.99100207861144063, 0.99157171773324027, 0.99112571824824358, 0.99031608691035722, 0.98978104266076905, 0.989782674787969, 0.98897835092187614, 0.98517540405423909, 0.98308943666187076, 0.96081810781994603, 0.85563541881892147, 0.61570811548079107, 0.33076276040577052, 0.14655134838124245, 0.076853147122142126, 0.035831324928136087, 0.021344669212790181])
my_y=my_y_raw/np.max(my_y_raw)

plt.plot(my_x, my_y,color='k', markersize=40)
plt.scatter(my_x,my_y,marker='*',label="myplot", color='k', edgecolor='k', linewidth=1,facecolors='none',s=50)
plt.legend(loc="lower left")
plt.xlim([4,102])

3 个答案:

答案 0 :(得分:2)

使用SciPy

进行插值的最直接方法是使用SciPy interpolate.interp1d函数。 SciPy与NumPy密切相关,您可能已经安装了它。 interp1d的优点是它可以为您排序数据。这是以一些有点时髦的语法为代价的。在许多插值函数中,假设您正在尝试从x值插值y值。这些函数通常需要“x”值单调递增。在你的情况下,我们交换正常的x和y意义。正如@Abhishek Mishra指出的那样,y值具有异常值。对于您的数据,您很幸运,您可以离开离开外线。

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d

my_x = [4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,
48,50,52,54,56,58,60,62,64,66]

my_y_raw=np.array([0.99470977497817203, 0.99434995886145172, 
0.98974611323163653, 0.961630837657524, 0.99327633558441175, 
0.99338952769251909, 0.99428263292577534, 0.98690514212711611, 
0.99111667721533181, 0.99149418924880861, 0.99133773062680464, 
0.99143506380003499, 0.99151080464011454, 0.99268261743308517, 
0.99289757252812316, 0.99100207861144063, 0.99157171773324027, 
0.99112571824824358, 0.99031608691035722, 0.98978104266076905, 
0.989782674787969, 0.98897835092187614, 0.98517540405423909, 
0.98308943666187076, 0.96081810781994603, 0.85563541881892147, 
0.61570811548079107, 0.33076276040577052, 0.14655134838124245, 
0.076853147122142126, 0.035831324928136087, 0.021344669212790181])

# set assume_sorted to have scipy automatically sort for you
f = interp1d(my_y_raw, my_x, assume_sorted = False)
xnew = f(0.5)

print('interpolated value is ', xnew)

plt.plot(my_x, my_y_raw,'x-', markersize=10)
plt.plot(xnew, 0.5, 'x', color = 'r', markersize=20)
plt.plot((0, xnew), (0.5,0.5), ':')
plt.grid(True)
plt.show()

给出了

interpolated value is  56.81214249272691

enter image description here

使用NumPy

Numpy也有一个interp功能,但它不适合你。如果你不排序,你会后悔的:

  

不检查x坐标序列xp是否正在增加。如果是xp   没有增加,结果是无稽之谈。

我能让np.interp工作的唯一方法就是将数据推送到结构化数组中。

import numpy as np
import matplotlib.pyplot as plt

my_x = np.array([4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,
48,50,52,54,56,58,60,62,64,66], dtype = np.float)


my_y_raw=np.array([0.99470977497817203, 0.99434995886145172, 
0.98974611323163653, 0.961630837657524, 0.99327633558441175, 
0.99338952769251909, 0.99428263292577534, 0.98690514212711611, 
0.99111667721533181, 0.99149418924880861, 0.99133773062680464, 
0.99143506380003499, 0.99151080464011454, 0.99268261743308517, 
0.99289757252812316, 0.99100207861144063, 0.99157171773324027, 
0.99112571824824358, 0.99031608691035722, 0.98978104266076905, 
0.989782674787969, 0.98897835092187614, 0.98517540405423909, 
0.98308943666187076, 0.96081810781994603, 0.85563541881892147, 
0.61570811548079107, 0.33076276040577052, 0.14655134838124245, 
0.076853147122142126, 0.035831324928136087, 0.021344669212790181], 
dtype = np.float)

dt = np.dtype([('x', np.float), ('y', np.float)])
data = np.zeros( (len(my_x)), dtype = dt)
data['x'] = my_x
data['y'] = my_y_raw

data.sort(order = 'y') # sort data in place by y values

print('numpy interp gives ', np.interp(0.5, data['y'], data['x']))

给出了

numpy interp gives  56.81214249272691

答案 1 :(得分:1)

正如您所说,您的数据看起来像是一个翻转的S形。我们可以假设你的函数是一个严格递减的函数吗?如果是这种情况,我们可以尝试以下方法:

  1. 删除数据未严格减少的所有点。例如,对于您的数据,该点将接近0。
  2. 使用二进制搜索来查找应该放入y = 0.5的位置。
  3. 现在你知道两个(x,y)对,你想要的y = 0.5应该在哪里。
  4. 如果(x,y)对非常接近,则可以使用简单的线性插值。
  5. 否则,你可以看到这些对附近的sigmoid的近似值。

答案 2 :(得分:1)

您可能不需要在数据中使用任何功能。只需找到以下两个元素:

  1. y <50%
  2. 的最大x
  3. y> 50%
  4. 的最小x

    然后使用插值找到x *。以下是代码

    my_x = np.array([4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66])
    my_y=np.array([0.99470977497817203, 0.99434995886145172, 0.98974611323163653, 0.961630837657524, 0.99327633558441175, 0.99338952769251909, 0.99428263292577534, 0.98690514212711611, 0.99111667721533181, 0.99149418924880861, 0.99133773062680464, 0.99143506380003499, 0.99151080464011454, 0.99268261743308517, 0.99289757252812316, 0.99100207861144063, 0.99157171773324027, 0.99112571824824358, 0.99031608691035722, 0.98978104266076905, 0.989782674787969, 0.98897835092187614, 0.98517540405423909, 0.98308943666187076, 0.96081810781994603, 0.85563541881892147, 0.61570811548079107, 0.33076276040577052, 0.14655134838124245, 0.076853147122142126, 0.035831324928136087, 0.021344669212790181])
    
    tempInd1 = my_y<.5 # This will only work if the values are monotonic
    
    x1 = my_x[tempInd1][0]
    y1 = my_y[tempInd1][0]
    
    x2 = my_x[~tempInd1][-1]
    y2 = my_y[~tempInd1][-1]
    
    scipy.interp(0.5, [y1, y2], [x1, x2])