Сегментированная регрессия в питоне с использованием дифференциальной эволюции - PullRequest
2 голосов
/ 11 июня 2019

У меня есть долгосрочная цель - создать модуль, который для конкретного набора данных подгоняет сегментированные регрессии вплоть до произвольного числа точек останова, а также стандартное полиномиальное и линейное соответствие кривой, а затем оценивает, какое из подгонокявляются наиболее подходящими для данных (вероятно, с использованием AIC или BIC).

У меня есть функция, которая использует дифференциальную эволюцию для использования сегментированной регрессии в наборе данных x и y, принимая 1 точку останова:

def segReg_one(xData,yData):

    def func(xVals,model_break,slopeA,slopeB,offsetA,offsetB): #Initialization of the piecewise function
        returnArray=[]
        for x in xVals:
            if x > model_break:
                returnArray.append(slopeA * x + offsetA)
            else:
                returnArray.append(slopeB * x + offsetB)


        return returnArray

    def sumSquaredError(parametersTuple): #Definition of an error function to minimize
        modely=func(xData,*parametersTuple)
        warnings.filterwarnings("ignore") # Ignore warnings by genetic algorithm

        return np.sum((yData-modely)**2.0)

    def generate_genetic_Parameters():
        initial_parameters=[]
        x_max=np.max(xData)
        x_min=np.min(xData)
        y_max=np.max(yData)
        y_min=np.min(yData)
        slope=10*(y_max-y_min)/(x_max-x_min)

        initial_parameters.append([x_max,x_min]) #Bounds for model break point
        initial_parameters.append([-slope,slope]) #Bounds for slopeA
        initial_parameters.append([-slope,slope]) #Bounds for slopeB
        initial_parameters.append([y_max,y_min]) #Bounds for offset A
        initial_parameters.append([y_max,y_min]) #Bounds for offset B

        result=differential_evolution(sumSquaredError,initial_parameters,seed=3)

        return result.x

    geneticParameters = generate_genetic_Parameters() #Generates genetic parameters



    fittedParameters, pcov= curve_fit(func, xData, yData, geneticParameters) #Fits the data 
    print('Parameters:', fittedParameters)
    print('Model break at: ', fittedParameters[0])
    print('Slope of line where x < model break: ', fittedParameters[1])
    print('Slope of line where x > model break: ', fittedParameters[2])
    print('Offset of line where x < model break: ', fittedParameters[3])
    print('Offset of line where x > model break: ', fittedParameters[4])





    model=func(xData,*fittedParameters)

    absError = model - yData

    SE = np.square(absError) 
    MSE = np.mean(SE) 
    RMSE = np.sqrt(MSE) 
    Rsquared = 1.0 - (np.var(absError) / np.var(yData))

    print()
    print('RMSE:', RMSE)
    print('R-squared:', Rsquared)



    def ModelAndScatterPlot(graphWidth, graphHeight):
            f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
            axes = f.add_subplot(111)


            axes.plot(xData, yData,  'D')

            xModel = np.linspace(min(xData), max(xData))
            yModel = func(xModel, *fittedParameters)

            axes.plot(xModel, yModel)

            axes.set_xlabel('X Data') # X axis data label
            axes.set_ylabel('Y Data') # Y axis data label

            plt.show()
            plt.close('all') 


    graphWidth = 800
    graphHeight = 600

    return ModelAndScatterPlot(800,600)

, которая работает нормально.Однако я попытался расширить модель, чтобы учесть более 1 точки останова:

def segReg_two(xData,yData):

    def func(xData,break1,break2,slope1,slope_mid,slope2,offset1,offset_mid,offset2):
        returnArray=[]
        for x in xData:
            if x < break1:
                returnArray.append(slope1 * x + offset1)

            if (x < break2 and x > break1):
                returnArray.append(slope_mid * x + offset_mid)

            else:
                returnArray.append(slope2 * x + offset2)


    def sumSquaredError(parametersTuple): #Definition of an error function to minimize
        modely=func(xData,*parametersTuple)
        warnings.filterwarnings("ignore") # Ignore warnings by genetic algorithm

        return np.sum((yData-modely)**2.0)

    def generate_genetic_Parameters():
        initial_parameters=[]
        x_max=np.max(xData)
        x_min=np.min(xData)
        y_max=np.max(yData)
        y_min=np.min(yData)
        slope=10*(y_max-y_min)/(x_max-x_min)

        initial_parameters.append([x_max,x_min]) #Bounds for model break point
        initial_parameters.append([x_max,x_min])
        initial_parameters.append([-slope,slope]) 
        initial_parameters.append([-slope,slope]) 
        initial_parameters.append([-slope,slope]) 
        initial_parameters.append([y_max,y_min])
        initial_parameters.append([y_max,y_min]) 
        initial_parameters.append([y_max,y_min]) 


        result=differential_evolution(sumSquaredError,initial_parameters,seed=3)

        return result.x

    geneticParameters = generate_genetic_Parameters() #Generates genetic parameters



    fittedParameters, pcov= curve_fit(func, xData, yData, geneticParameters) #Fits the data 
    print('Parameters:', fittedParameters)
    print('Model break at: ', fittedParameters[0])
    print('Slope of line where x < model break: ', fittedParameters[1])
    print('Slope of line where x > model break: ', fittedParameters[2])
    print('Offset of line where x < model break: ', fittedParameters[3])
    print('Offset of line where x > model break: ', fittedParameters[4])





    model=func(xData,*fittedParameters)

    absError = model - yData

    SE = np.square(absError) 
    MSE = np.mean(SE) 
    RMSE = np.sqrt(MSE) 
    Rsquared = 1.0 - (np.var(absError) / np.var(yData))

    print()
    print('RMSE:', RMSE)
    print('R-squared:', Rsquared)

    def ModelAndScatterPlot(graphWidth, graphHeight):
            f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
            axes = f.add_subplot(111)


            axes.plot(xData, yData,  'D')

            xModel = np.linspace(min(xData), max(xData))
            yModel = func(xModel, *fittedParameters)

            axes.plot(xModel, yModel)

            axes.set_xlabel('X Data') # X axis data label
            axes.set_ylabel('Y Data') # Y axis data label

            plt.show()
            plt.close('all') 


    graphWidth = 800
    graphHeight = 600

    return ModelAndScatterPlot(800,600)

И этот код сталкивается с проблемами при запуске segReg_two(x,y), останавливаясь на бите differential_evolution:

TypeError: неподдерживаемые типы операндов для -: 'float' и 'NoneType' Во время обработки вышеупомянутого исключения произошло другое исключение:

RuntimeError: должен вызываться вызов типа картыформа f (func, iterable), возвращающая последовательность чисел той же длины, что и 'iterable'

У меня не было этой проблемы с segReg_one, поэтому я не понимаю, почему яУ меня это случилось здесь.Я предполагаю (и я могу ошибаться в этом предположении), что аргумент iterable должен иметь совместимые измерения с моей функцией ошибок.Тем не менее, я не совсем уверен в том, как эти два аргумента в точности связаны друг с другом, кроме того, что я нахожу точки останова, наклоны и смещения, которые минимизируют точки останова с учетом имеющихся у меня границ.

Кроме того, мой планатаки кажутся чрезвычайно затянутыми и жестокими.Есть ли лучший способ справиться с этим?

Я думаю, возможно, это рассматривает мою кусочную функцию как None-type.Печать функции с некоторыми случайными значениями вернула просто «Нет».Тем не менее, моя кусочная функция печатает то же самое, и она все еще работала нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...