univariate_tools.interpolation

Interpolation holds classes and functions important for interpolating data

  1#-----------------------------------------------------------------------------
  2# Name:        Interpolation
  3# Purpose:     To hold functions and classes for interpolating data
  4# Author:      Aric Sanders
  5# Created:     04/03/2025
  6# License:     MIT License
  7#-----------------------------------------------------------------------------
  8""" Interpolation holds classes and functions important for interpolating data
  9
 10 """
 11
 12#-----------------------------------------------------------------------------
 13# Standard Imports
 14import os
 15import sys
 16import re
 17#-----------------------------------------------------------------------------
 18# Third Party Imports
 19sys.path.append(os.path.join(os.path.dirname( __file__ ), '..'))
 20import matplotlib.pyplot as plt
 21import numpy as np
 22from scipy import interpolate
 23from sklearn.gaussian_process import GaussianProcessRegressor
 24from sklearn.gaussian_process.kernels import RBF
 25from scipy.interpolate import make_smoothing_spline
 26import statsmodels.api as sm
 27from scipy import signal
 28from skmisc.loess import loess
 29import scipy
 30#-----------------------------------------------------------------------------
 31# Module Constants
 32
 33#-----------------------------------------------------------------------------
 34# Module Functions
 35
 36
 37def reverse_regressor(x_data,y_data,new_y_data,method="lowess",**options):
 38    """reverse_regressor returns a series of new_x_data points given observed x_data, y_data and the desired 
 39    new_y_data. This function is intended as a wrapper to create a clean interface to the large number of interpolation
 40    possibilities.
 41    
 42    Current methods are lowess,loess, 1d, gpr and spline. 
 43    *********************************************************************************************
 44    refs: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html, options for kind are
 45    ‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, 
 46    ‘quadratic’, ‘cubic’, ‘previous’, or ‘next’. ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’
 47    ****************************************************************************************
 48    https://www.statsmodels.org/dev/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html
 49    ***********************************************************************************************
 50    https://has2k1.github.io/scikit-misc/stable/index.html
 51    ******************************************************
 52    https://scikit-learn.org/stable/modules/gaussian_process.html
 53    ***************************************************************
 54    https://docs.scipy.org/doc/scipy/tutorial/interpolate/smoothing_splines.html
 55    ********************************************************************************"""
 56    defaults = {}
 57    interpolation_options = {}
 58    for key,value in defaults.items():
 59        interpolation_options[key] = value
 60    for key, value in options.items():
 61        interpolation_options[key] = value
 62    new_x_data = None 
 63        
 64    if re.search("lowess",method,re.IGNORECASE):
 65        lowess_key_words = ['frac']
 66        lowess_options = {'frac':.2}
 67        for key,value in interpolation_options.items():
 68            if key in lowess_key_words:
 69                lowess_options[key]=value
 70        interpolation_result= sm.nonparametric.lowess(endog=x_data,
 71                                                      exog=y_data,
 72                                                      xvals = new_y_data,
 73                                                      **lowess_options)
 74        new_x_data = interpolation_result
 75        
 76    if re.search("loess",method,re.IGNORECASE):
 77        loess_key_words = ['p','span','family','degree','normalize']
 78        loess_options = {"span":0.65, "p":1, "family":'gaussian', "degree":1, "normalize":False}
 79        for key,value in interpolation_options.items():
 80            if key in loess_key_words:
 81                loess_options[key]=value
 82        lo = loess(y_data, x_data, **loess_options)
 83        lo.fit()
 84        pred = lo.predict(new_y_data, stderror=True)
 85        new_x_data = np.array(pred.values)
 86        
 87    if re.search("1d",method,re.IGNORECASE):
 88        interp1d_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
 89        interp1d_options ={"fill_value":"extrapolate"}
 90        for key,value in interpolation_options.items():
 91            if key in interp1d_key_words:
 92                interp1d_options[key]=value
 93        interpolation_function = scipy.interpolate.interp1d(y_data,
 94                                   x_data,**interp1d_options)
 95        new_x_data = interpolation_function(new_y_data)
 96        
 97    elif re.search("gpr",method,re.IGNORECASE):
 98        gpr_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
 99        gpr_options ={"kernel":1 * RBF(length_scale=1.0, length_scale_bounds=(1e-2, 1e2)),
100                     "n_restarts_optimizer":9}
101        for key,value in interpolation_options.items():
102            if key in gpr_key_words:
103                gpr_options[key]=value
104
105        gaussian_process = GaussianProcessRegressor(**gpr_options)
106        gaussian_process.fit(y_data.reshape(-1,1), x_data)
107        mean_prediction, std_prediction = gaussian_process.predict(new_y_data.reshape(-1,1), return_std=True)
108        new_x_data = mean_prediction
109        
110    elif re.search("spline",method,re.IGNORECASE):
111        coordinates = zip(y_data,x_data)
112        ordered_array = np.array(sorted(coordinates))        
113        interpolation_function = scipy.interpolate.make_smoothing_spline(ordered_array.T[0],ordered_array.T[1])
114        new_x_data = interpolation_function(new_y_data)   
115
116    return new_x_data    
117
118def interpolate_data(x_data,y_data,new_x_data,method="lowess",**options):
119    """interpolate_data returns a series of new_y_data points given observed x_data, y_data and the desired 
120    new_x_data. This function is intended as a wrapper to create a clean interface to the large number of interpolation
121    possibilites. Current methods are lowess,loess, 1d, gpr and spline. 
122    *********************************************************************************************
123    refs: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html, options for kind are
124    ‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, 
125    ‘quadratic’, ‘cubic’, ‘previous’, or ‘next’. ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’
126    ****************************************************************************************
127    https://www.statsmodels.org/dev/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html
128    ***********************************************************************************************
129    https://scikit-learn.org/stable/modules/gaussian_process.html
130    ***************************************************************
131    https://docs.scipy.org/doc/scipy/tutorial/interpolate/smoothing_splines.html
132    ********************************************************************************"""
133    defaults = {}
134    interpolation_options = {}
135    for key,value in defaults.items():
136        interpolation_options[key] = value
137    for key, value in options.items():
138        interpolation_options[key] = value
139    new_y_data = None 
140        
141    if re.search("lowess",method,re.IGNORECASE):
142        lowess_key_words = ['frac']
143        lowess_options = {}
144        for key,value in interpolation_options.items():
145            if key in lowess_key_words:
146                lowess_options[key]=value
147        interpolation_result= sm.nonparametric.lowess(y_data,
148                                                      x_data,
149                                                      xvals = new_x_data,
150                                                      **lowess_options)
151        new_y_data = interpolation_result
152        
153            
154    if re.search("loess",method,re.IGNORECASE):
155        loess_key_words = ['p','span','family','degree','normalize']
156        loess_options = {"span":0.65, "p":1, "family":'gaussian', "degree":1, "normalize":False}
157        for key,value in interpolation_options.items():
158            if key in loess_key_words:
159                loess_options[key]=value
160        lo = loess(x_data, y_data, **loess_options)
161        lo.fit()
162        pred = lo.predict(new_x_data, stderror=True)
163        new_y_data = np.array(pred.values)
164        
165    if re.search("1d",method,re.IGNORECASE):
166        interp1d_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
167        interp1d_options ={"fill_value":"extrapolate"}
168        for key,value in interpolation_options.items():
169            if key in interp1d_key_words:
170                interp1d_options[key]=value
171        interpolation_function = scipy.interpolate.interp1d(x_data,
172                                   y_data,**interp1d_options)
173        new_y_data = interpolation_function(new_x_data)
174        
175    elif re.search("gpr",method,re.IGNORECASE):
176        gpr_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
177        gpr_options ={"kernel":1 * RBF(length_scale=1.0, length_scale_bounds=(1e-2, 1e2)),
178                     "n_restarts_optimizer":9}
179        for key,value in interpolation_options.items():
180            if key in gpr_key_words:
181                gpr_options[key]=value
182        gaussian_process = GaussianProcessRegressor(**gpr_options)
183        gaussian_process.fit(x_data.reshape(-1,1), y_data)
184        mean_prediction, std_prediction = gaussian_process.predict(new_x_data.reshape(-1,1), return_std=True)
185        new_y_data = mean_prediction
186        
187    elif re.search("spline",method,re.IGNORECASE):
188        coordinates = zip(x_data,y_data)
189        ordered_array = np.array(sorted(coordinates))        
190        interpolation_function = scipy.interpolate.make_smoothing_spline(ordered_array.T[0],ordered_array.T[1])
191        new_y_data = interpolation_function(new_x_data)
192        
193    return new_y_data
194
195
196
197
198
199#-----------------------------------------------------------------------------
200# Module Classes
201
202#-----------------------------------------------------------------------------
203# Module Scripts
204def test_interpolate_data():
205    x_data = np.linspace(-6,6,500)
206    signal = np.sin(x_data)+np.random.normal(scale=.5,size=len(x_data))
207    plt.plot(x_data,signal,".",label="Original Data")
208    for interp_type in ["lowess","loess", "1d", "gpr","spline"]:
209        new_x = np.linspace(-2,2,500)
210        interp_data = interpolate_data(x_data=x_data,y_data=signal,new_x_data=new_x,method=interp_type)
211        plt.plot(new_x,interp_data,label=interp_type)
212    plt.legend()
213    plt.show()
214
215def test_reverse_regressor():
216    x_data = np.linspace(-6,6,200)
217    signal = 2*x_data+1+np.random.normal(scale=.2,size=len(x_data))
218    plt.plot(x_data,signal,".",label="Original Data",alpha=.3)
219
220    for interp_type in ["lowess","loess", "1d", "gpr","spline"]:
221        try:
222            new_y = np.linspace(-2,5,10)
223            new_x = reverse_regressor(x_data=x_data,y_data=signal,new_y_data=new_y,method=interp_type)
224            print(f"{interp_type}:{new_x},{new_y}")
225            plt.plot(new_x,new_y,label=interp_type,linewidth=2,linestyle="dashed")
226        except Exception as e:
227            print(e)
228    plt.legend()
229    plt.show()
230
231def test_lowess():
232    x_data = np.linspace(-6,6,100)
233    y_data = 2*x_data+1+np.random.normal(scale=.1,size=len(x_data))
234    new_y_data = np.linspace(-2,5,10)
235    interpolation_result= sm.nonparametric.lowess(endog=x_data,
236                                                    exog=y_data,
237                                                    xvals = new_y_data,
238                                                    frac=.2)
239    #print(interpolation_result)
240    new_x = reverse_regressor(x_data=x_data,y_data=y_data,new_y_data=new_y_data,method="lowess")
241    plt.plot(x_data,y_data,label="original data")
242    plt.plot(interpolation_result,new_y_data,label="lowess fit")
243    plt.plot(new_x,new_y_data,label="lowess fit 2")
244    plt.show()
245
246#-----------------------------------------------------------------------------
247# Module Runner
248if __name__ == '__main__':
249    #test_interpolate_data()
250    test_reverse_regressor()
251    #test_lowess()
def reverse_regressor(x_data, y_data, new_y_data, method='lowess', **options):
 38def reverse_regressor(x_data,y_data,new_y_data,method="lowess",**options):
 39    """reverse_regressor returns a series of new_x_data points given observed x_data, y_data and the desired 
 40    new_y_data. This function is intended as a wrapper to create a clean interface to the large number of interpolation
 41    possibilities.
 42    
 43    Current methods are lowess,loess, 1d, gpr and spline. 
 44    *********************************************************************************************
 45    refs: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html, options for kind are
 46    ‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, 
 47    ‘quadratic’, ‘cubic’, ‘previous’, or ‘next’. ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’
 48    ****************************************************************************************
 49    https://www.statsmodels.org/dev/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html
 50    ***********************************************************************************************
 51    https://has2k1.github.io/scikit-misc/stable/index.html
 52    ******************************************************
 53    https://scikit-learn.org/stable/modules/gaussian_process.html
 54    ***************************************************************
 55    https://docs.scipy.org/doc/scipy/tutorial/interpolate/smoothing_splines.html
 56    ********************************************************************************"""
 57    defaults = {}
 58    interpolation_options = {}
 59    for key,value in defaults.items():
 60        interpolation_options[key] = value
 61    for key, value in options.items():
 62        interpolation_options[key] = value
 63    new_x_data = None 
 64        
 65    if re.search("lowess",method,re.IGNORECASE):
 66        lowess_key_words = ['frac']
 67        lowess_options = {'frac':.2}
 68        for key,value in interpolation_options.items():
 69            if key in lowess_key_words:
 70                lowess_options[key]=value
 71        interpolation_result= sm.nonparametric.lowess(endog=x_data,
 72                                                      exog=y_data,
 73                                                      xvals = new_y_data,
 74                                                      **lowess_options)
 75        new_x_data = interpolation_result
 76        
 77    if re.search("loess",method,re.IGNORECASE):
 78        loess_key_words = ['p','span','family','degree','normalize']
 79        loess_options = {"span":0.65, "p":1, "family":'gaussian', "degree":1, "normalize":False}
 80        for key,value in interpolation_options.items():
 81            if key in loess_key_words:
 82                loess_options[key]=value
 83        lo = loess(y_data, x_data, **loess_options)
 84        lo.fit()
 85        pred = lo.predict(new_y_data, stderror=True)
 86        new_x_data = np.array(pred.values)
 87        
 88    if re.search("1d",method,re.IGNORECASE):
 89        interp1d_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
 90        interp1d_options ={"fill_value":"extrapolate"}
 91        for key,value in interpolation_options.items():
 92            if key in interp1d_key_words:
 93                interp1d_options[key]=value
 94        interpolation_function = scipy.interpolate.interp1d(y_data,
 95                                   x_data,**interp1d_options)
 96        new_x_data = interpolation_function(new_y_data)
 97        
 98    elif re.search("gpr",method,re.IGNORECASE):
 99        gpr_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
100        gpr_options ={"kernel":1 * RBF(length_scale=1.0, length_scale_bounds=(1e-2, 1e2)),
101                     "n_restarts_optimizer":9}
102        for key,value in interpolation_options.items():
103            if key in gpr_key_words:
104                gpr_options[key]=value
105
106        gaussian_process = GaussianProcessRegressor(**gpr_options)
107        gaussian_process.fit(y_data.reshape(-1,1), x_data)
108        mean_prediction, std_prediction = gaussian_process.predict(new_y_data.reshape(-1,1), return_std=True)
109        new_x_data = mean_prediction
110        
111    elif re.search("spline",method,re.IGNORECASE):
112        coordinates = zip(y_data,x_data)
113        ordered_array = np.array(sorted(coordinates))        
114        interpolation_function = scipy.interpolate.make_smoothing_spline(ordered_array.T[0],ordered_array.T[1])
115        new_x_data = interpolation_function(new_y_data)   
116
117    return new_x_data    

reverse_regressor returns a series of new_x_data points given observed x_data, y_data and the desired new_y_data. This function is intended as a wrapper to create a clean interface to the large number of interpolation possibilities.

Current methods are lowess,loess, 1d, gpr and spline.


refs: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html, options for kind are ‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘previous’, or ‘next’. ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’


https://www.statsmodels.org/dev/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html


https://has2k1.github.io/scikit-misc/stable/index.html


https://scikit-learn.org/stable/modules/gaussian_process.html


https://docs.scipy.org/doc/scipy/tutorial/interpolate/smoothing_splines.html


def interpolate_data(x_data, y_data, new_x_data, method='lowess', **options):
119def interpolate_data(x_data,y_data,new_x_data,method="lowess",**options):
120    """interpolate_data returns a series of new_y_data points given observed x_data, y_data and the desired 
121    new_x_data. This function is intended as a wrapper to create a clean interface to the large number of interpolation
122    possibilites. Current methods are lowess,loess, 1d, gpr and spline. 
123    *********************************************************************************************
124    refs: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html, options for kind are
125    ‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, 
126    ‘quadratic’, ‘cubic’, ‘previous’, or ‘next’. ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’
127    ****************************************************************************************
128    https://www.statsmodels.org/dev/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html
129    ***********************************************************************************************
130    https://scikit-learn.org/stable/modules/gaussian_process.html
131    ***************************************************************
132    https://docs.scipy.org/doc/scipy/tutorial/interpolate/smoothing_splines.html
133    ********************************************************************************"""
134    defaults = {}
135    interpolation_options = {}
136    for key,value in defaults.items():
137        interpolation_options[key] = value
138    for key, value in options.items():
139        interpolation_options[key] = value
140    new_y_data = None 
141        
142    if re.search("lowess",method,re.IGNORECASE):
143        lowess_key_words = ['frac']
144        lowess_options = {}
145        for key,value in interpolation_options.items():
146            if key in lowess_key_words:
147                lowess_options[key]=value
148        interpolation_result= sm.nonparametric.lowess(y_data,
149                                                      x_data,
150                                                      xvals = new_x_data,
151                                                      **lowess_options)
152        new_y_data = interpolation_result
153        
154            
155    if re.search("loess",method,re.IGNORECASE):
156        loess_key_words = ['p','span','family','degree','normalize']
157        loess_options = {"span":0.65, "p":1, "family":'gaussian', "degree":1, "normalize":False}
158        for key,value in interpolation_options.items():
159            if key in loess_key_words:
160                loess_options[key]=value
161        lo = loess(x_data, y_data, **loess_options)
162        lo.fit()
163        pred = lo.predict(new_x_data, stderror=True)
164        new_y_data = np.array(pred.values)
165        
166    if re.search("1d",method,re.IGNORECASE):
167        interp1d_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
168        interp1d_options ={"fill_value":"extrapolate"}
169        for key,value in interpolation_options.items():
170            if key in interp1d_key_words:
171                interp1d_options[key]=value
172        interpolation_function = scipy.interpolate.interp1d(x_data,
173                                   y_data,**interp1d_options)
174        new_y_data = interpolation_function(new_x_data)
175        
176    elif re.search("gpr",method,re.IGNORECASE):
177        gpr_key_words = ["kind","axis","copy","bounds_error","fill_value","assume_sorted"]
178        gpr_options ={"kernel":1 * RBF(length_scale=1.0, length_scale_bounds=(1e-2, 1e2)),
179                     "n_restarts_optimizer":9}
180        for key,value in interpolation_options.items():
181            if key in gpr_key_words:
182                gpr_options[key]=value
183        gaussian_process = GaussianProcessRegressor(**gpr_options)
184        gaussian_process.fit(x_data.reshape(-1,1), y_data)
185        mean_prediction, std_prediction = gaussian_process.predict(new_x_data.reshape(-1,1), return_std=True)
186        new_y_data = mean_prediction
187        
188    elif re.search("spline",method,re.IGNORECASE):
189        coordinates = zip(x_data,y_data)
190        ordered_array = np.array(sorted(coordinates))        
191        interpolation_function = scipy.interpolate.make_smoothing_spline(ordered_array.T[0],ordered_array.T[1])
192        new_y_data = interpolation_function(new_x_data)
193        
194    return new_y_data

interpolate_data returns a series of new_y_data points given observed x_data, y_data and the desired new_x_data. This function is intended as a wrapper to create a clean interface to the large number of interpolation possibilites. Current methods are lowess,loess, 1d, gpr and spline.


refs: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html, options for kind are ‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘previous’, or ‘next’. ‘zero’, ‘slinear’, ‘quadratic’ and ‘cubic’


https://www.statsmodels.org/dev/generated/statsmodels.nonparametric.smoothers_lowess.lowess.html


https://scikit-learn.org/stable/modules/gaussian_process.html


https://docs.scipy.org/doc/scipy/tutorial/interpolate/smoothing_splines.html


def test_interpolate_data():
205def test_interpolate_data():
206    x_data = np.linspace(-6,6,500)
207    signal = np.sin(x_data)+np.random.normal(scale=.5,size=len(x_data))
208    plt.plot(x_data,signal,".",label="Original Data")
209    for interp_type in ["lowess","loess", "1d", "gpr","spline"]:
210        new_x = np.linspace(-2,2,500)
211        interp_data = interpolate_data(x_data=x_data,y_data=signal,new_x_data=new_x,method=interp_type)
212        plt.plot(new_x,interp_data,label=interp_type)
213    plt.legend()
214    plt.show()
def test_reverse_regressor():
216def test_reverse_regressor():
217    x_data = np.linspace(-6,6,200)
218    signal = 2*x_data+1+np.random.normal(scale=.2,size=len(x_data))
219    plt.plot(x_data,signal,".",label="Original Data",alpha=.3)
220
221    for interp_type in ["lowess","loess", "1d", "gpr","spline"]:
222        try:
223            new_y = np.linspace(-2,5,10)
224            new_x = reverse_regressor(x_data=x_data,y_data=signal,new_y_data=new_y,method=interp_type)
225            print(f"{interp_type}:{new_x},{new_y}")
226            plt.plot(new_x,new_y,label=interp_type,linewidth=2,linestyle="dashed")
227        except Exception as e:
228            print(e)
229    plt.legend()
230    plt.show()
def test_lowess():
232def test_lowess():
233    x_data = np.linspace(-6,6,100)
234    y_data = 2*x_data+1+np.random.normal(scale=.1,size=len(x_data))
235    new_y_data = np.linspace(-2,5,10)
236    interpolation_result= sm.nonparametric.lowess(endog=x_data,
237                                                    exog=y_data,
238                                                    xvals = new_y_data,
239                                                    frac=.2)
240    #print(interpolation_result)
241    new_x = reverse_regressor(x_data=x_data,y_data=y_data,new_y_data=new_y_data,method="lowess")
242    plt.plot(x_data,y_data,label="original data")
243    plt.plot(interpolation_result,new_y_data,label="lowess fit")
244    plt.plot(new_x,new_y_data,label="lowess fit 2")
245    plt.show()