Omar ELAMIRI
Omar ELAMIRI

Reputation: 21

How to perform a cross-Validation on Piecewise Model using Symfit or curve_fit?

I am trying to perform a cross-Validation on Piecewise Model using Symfit :

My Data :

x_data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], dtype=float)
y_data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10])

to use cross validation we need to create an estimator, so i tried to package the fitting in a class

from sklearn.model_selection import cross_validate, cross_val_score
class model:
    def __init__( self, a=None, b=None, c=None ):
        self.a = a
        self.b = b
        self.c = c 
        
    def _model_background(self, X, a, b, c):
        y1 = a*x + b-a*c
        y2 = b
        return Model({y: Piecewise((y1, x <= c), (y2, x > c))})

    def predict( self, X ):
        return self._model_background( X, self.a, self.b, self.c ) 

    def fit( self, X, y ):
        from symfit import parameters, variables, Fit, Piecewise, Model
        fit = Fit(self._model_background, x=x_data, y=y_data)
        fit_result = fit.execute()
        self.a = fit_result.value(a)
        self.b = fit_result.value(b)
        self.c = fit_result.value(c)
        return self

    def get_params( self, deep=False ):
        return { 'a':self.a, 'b':self.b, 'c':self.c }

    def set_params( self, **parameters ):
        for parameter, value in parameters.intems():
            setattr( self, parameter, value )
        return self

and then I perform the cross-validation line

cross_validate( symfitmodel(), x_data, y_data, cv=5, scoring='neg_mean_squared_error' )

But it seems that I didn't create the class as it should Error message :

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\model_selection\_validation.py:548: FitFailedWarning: Estimator fit failed. The score on this train-test partition for these parameters will be set to nan. Details: 
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\support.py", line 282, in __get__
    return getattr(obj, self.cache_attr)
AttributeError: 'Model' object has no attribute '_cached_connectivity_mapping'

During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\sklearn\model_selection\_validation.py", line 531, in _fit_and_score
    estimator.fit(X_train, y_train, **fit_params)
  File "<ipython-input-3-db68eb82746d>", line 18, in fit
    fit = Fit(self._model_background, x=x_data, y=y_data)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\support.py", line 423, in wrapped_func
    return func(*bound_args.args, **bound_args.kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\fit.py", line 374, in __init__
    self.model = Model(model)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\models.py", line 875, in __init__
    super(HessianModel, self).__init__(*args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\models.py", line 824, in __init__
    super(GradientModel, self).__init__(*args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\models.py", line 125, in __init__
    self._init_from_dict(model)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\models.py", line 651, in _init_from_dict
    super(BaseCallableModel, self)._init_from_dict(model_dict)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\models.py", line 309, in _init_from_dict
    ordered = list(toposort(self.connectivity_mapping))
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\support.py", line 285, in __get__
    setattr(obj, self.cache_attr, self.fget(obj))
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\models.py", line 383, in connectivity_mapping
    vars, params = seperate_symbols(expr)
  File "C:\ProgramData\Anaconda3\lib\site-packages\symfit\core\support.py", line 82, in seperate_symbols
    for symbol in func.free_symbols:
AttributeError: 'function' object has no attribute 'free_symbols'

  warnings.warn("Estimator fit failed. The score on this train-test"

I tried it with curve_fit but without success:

class piecewise:    
    def __init__( self, x0=None, a=None, b=None ):
        self.x0 = x0
        self.a = a
        self.b = b 
        
    def _piecewise_background(self, X, x0, a, b):
        return np.piecewise(X, [X < x0], [lambda X:a*X + b-a*x0, lambda X:b])

    def predict( self, X ):
        return self._piecewise_background( X, self.x0, self.a, self.b ) 

    def fit( self, X, y ):
        from scipy.optimize import curve_fit
        popt, pcov = curve_fit( self._piecewise_background, X, y ) 
        self.x0 = popt[0]
        self.a = popt[1]
        self.b = popt[2]
        return self

    def get_params( self, deep=False ):
        return { 'x0':self.x0, 'a':self.a, 'b':self.b }

    def set_params( self, **parameters ):
        for parameter, value in parameters.intems():
            setattr( self, parameter, value )
        return self

Any ideas ?

Upvotes: 0

Views: 242

Answers (1)

JJacquelin
JJacquelin

Reputation: 1705

This is not an answer but a comment.

A direct method (not iterative, no guessed initial value) is shown in the paper : https://fr.scribd.com/document/380941024/Regression-par-morceaux-Piecewise-Regression-pdf ( Page 8 in the present case).

Of course the data given in the question is of few interest because there is no scatter. So no need for numerical calculus the result is obvious. But this can be used to test the method of piecewise regression.

enter image description here

EXAMPLE with SCATTERED DATA

In order to make it more representative the above data has been scattered. Example below :

enter image description here

Upvotes: 0

Related Questions