Home > Software design >  Interpolation function for single data point
Interpolation function for single data point

Time:08-25

I'm using the interp1d function for interpolation

from scipy.interpolate import interp1d
x = [0, 3, 6, 10, 15, 20]
y = [1.87, 1.76, 1.27, 1.185, 0.995, 0.855]
f = interp1d(x, y, bounds_error=False)

x_find = [0, 5, 8, 10, 28]
print(f(x_find))

Using bounds_error=False in f = interp1d(x, y, bounds_error=False) returns nan value for x=28 in x_find. Since interp1d raises an error for single datapoints, I tried the following for single datapoint.

x0 = [1.87]
y0 = [0.93]
f0 = lambda x: y0[0] if np.isclose(x, x0[0]) else np.NaN
print(f0(x0[0]))

This doesn't work when I try f0(x_find).

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Expected output: f0(x_find) returns nan for values of x in x_find not present in x0like how bounds_error works.

Suggestions on how to do this will be really helpful

EDIT:

Question:

Would it be possible to modify the interpolation function of the single datapoint so that we could do just f(x_find), something similar to the one returned by f = interp1d() ?

CodePudding user response:

I just only guess that you are missing a very simple thing: to put a single value to the f0() function using a list comprehension to get all values in case of a list with values.

Does the following code:

import numpy as np
from scipy.interpolate import interp1d
x = [0, 3, 6, 10, 15, 20]
y = [1.87, 1.76, 1.27, 1.185, 0.995, 0.855]
f = interp1d(x, y, bounds_error=False)

x_find = [0, 5, 8, 10, 28]
print(f(x_find))
x0 = [1.87]
y0 = [0.93]
f0 = lambda x: y0[0] if np.isclose(x, x0[0]) else np.NaN
print(f0(x0[0]))

print([f0(x) for x in x_find])

which prints:

[1.87       1.43333333 1.2275     1.185             nan]
0.93
[nan, nan, nan, nan, nan]

meet your expectations?

You can also redefine f0 to cover the case of passing a list of values to it as follows:

def f0(x): 
    import numpy as np
    x0 = [1.87]
    y0 = [0.93]
    f = lambda x: y0[0] if np.isclose(x, x0[0]) else np.NaN
    if isinstance(x, list):
        return [f(z) for z in x]
    elif isinstance(x, float):
        return f(x)
    else:
        return "f0() accepts only float and lists of floats as parameter"
print('---')
print(f0(1.87))
print(f0(x_find))
print(f0("5"))

The output of the code above is:

---
0.93
[nan, nan, nan, nan, nan]
f0() accepts only float and lists of floats as parameter

FINALLY you can also redefine f0 as f_i which is a bit complex code simulating the behavior of scipy interp1d as follows:

def f_i(X=[1.87], Y=[0.93], bounds_error=False):
    # ToDo: implementation of bounds_error evaluation
    
    import numpy as np

    def f(v):
        for i, x in enumerate(X):
            if np.isclose(v, x):
                return Y[i]
        else:
            return np.NaN

    def r_f(w): 
        if isinstance(w, list):
            return [f(z) for z in w]
        elif isinstance(w, float):
            return f(w)
        else:
            return "ValueErrorMessage: param. not float or list of floats"
            
    return r_f
    
y = [1.87, 1.76, 1.27, 1.185, 0.995, 0.855]
x = [ 0,    3,    6,     10,    15,    20 ]

print('---')

f = f_i()
print(f(1.87))

f = f_i(x, y)
x_find = [0, 5, 8, 10, 28]
print(f(x_find))

print(f("5"))

which gives following output:

---
0.93
[1.87, nan, nan, 1.185, nan]
ValueErrorMessage: param. not float or list of floats
  • Related