1

I have to use an older scipy version, which can not extrapolate. In scipy 1.1.0 the extrapolation is working as expected, giving proper results. Since I cannot use this in my application I want to use numpy polyfit. but the results are different, while interpolation from scipy and bisect results are the same..

class InterExtraPolate(object):
  def __init__(self, x_list, y_list):
    if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
      raise ValueError("x_list must be in strictly ascending order!")
    self.x_list = map(float, x_list)
    self.y_list = map(float, y_list)
  def __getitem__(self, x):
    from scipy import interpolate
    f=interpolate.interp1d(self.x_list,self.y_list, fill_value='extrapolate')
    return f(x)


class npInterExraPolate(object):
  def __init__(self, x_list, y_list):
    import numpy as np
    if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
      raise ValueError("x_list must be in strictly ascending order!")
    self.x_list = map(float, x_list)
    self.y_list = map(float, y_list)
    self.fit=np.polyfit(self.x_list,self.y_list, 1)

  def __getitem__(self, x):
    import numpy as np
    f=np.poly1d(self.fit)
    return f(x)

##Main


ie   =  InterExtraPolate([1, 2.5, 3.4, 5.8, 6], [2, 4, 5.8, 4.3, 4])
npie = npInterExraPolate([1, 2.5, 3.4, 5.8, 6], [2, 4, 5.8, 4.3, 4])

my_xl = [0.5,1.1,6.3]

print ie[my_xl]

print npie[my_xl]

==== How can I make the numpy polyfit/poly1d results equal to the scipy extrapolate results?

reintl
  • 21
  • 2

2 Answers2

4

If you draw the actual results, you'll quickly see why a linear interpolation is not a linear fit: the interpolation works from point to point, while the fit takes all points into account: enter image description here

That doesn't explain how to do it properly, but should explain why it fails.

I see no way to use a polynomial fit as an alternative to interpolation, with exactly the same result.

You'll either have to code the interpolation yourself, or find a way to install a more recent version of SciPy.

For starters, have a look if you can use the --user option when installing SciPy. You don't mention why you have to use an older one, and what's preventing you from installing a newer version. That may be another question to ask: how to circumvent whatever limitiations there are in installing an up-to-date version of SciPy.

9769953
  • 10,344
  • 3
  • 26
  • 37
  • Thank you for explanation. The reason for unable to update is that this version is included as a 'tool' in a major application executable. From 2016. The updated version 2018 can use scipy 1.1.x. The enduser cannot upgrade at thi moment. – reintl May 26 '18 at 23:13
1

I solved for my needs using bisect_left and adding the extrapolated section in same slop as outer slopes..

class bsInterExtraPolate(object):
  def __init__(self, x_list, y_list):
    if any(y - x <= 0 for x, y in zip(x_list, x_list[1:])):
      raise ValueError("x_list must be in strictly ascending order!")
    x_list = self.x_list = map(float, x_list)
    y_list = self.y_list = map(float, y_list)
    intervals = zip(x_list, x_list[1:], y_list, y_list[1:])
    self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals]

  def __getitem__(self, x):
    #-- expanding for lin extrapolation using outer slopes
    from bisect import bisect_left
    if type(x)==list:
      yval=[]
      for xval in x:
        if xval < self.x_list[0]:
          i=0
        elif xval > self.x_list[-1]:
          i=len(self.x_list)-2
        else:
          i = bisect_left(self.x_list, xval) - 1
        ytmp=self.y_list[i] + self.slopes[i] * (xval - self.x_list[i])
        yval.append(ytmp)
    else:
      xval=float(x)
      if xval < self.x_list[0]:
        i=0
      elif xval > self.x_list[-1]:
        i=len(self.x_list)-2
      else:
        i = bisect_left(self.x_list, xval) - 1
      ytmp=self.y_list[i] + self.slopes[i] * (xval - self.x_list[i])
      yval=ytmp
    return yval
reintl
  • 21
  • 2