【发布时间】:2019-10-26 03:04:40
【问题描述】:
我的长期目标是创建一个模块,该模块适用于特定数据集,可将分段回归拟合到任意数量的断点,以及标准多项式和线性曲线拟合,然后评估哪些拟合最适合数据(可能使用 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: map-like callable 必须是 f(func, iterable) 的形式,返回一个与 'iterable' 长度相同的数字序列
segReg_one 没有这个问题,所以我不明白为什么会在这里发生。我假设(我可能对这个假设不正确)参数iterable 必须具有与我的误差函数兼容的尺寸。但是,我不确定这两个参数是如何准确关联的,除了我找到了断点、斜率和偏移量,这些断点、斜率和偏移量可以在给定边界的情况下最小化断点。
另外,我的进攻计划似乎非常冗长和野蛮。有没有更好的方法来解决这个问题?
我认为它可能将我的分段函数视为无类型。打印带有一些随机值的函数仅返回“无”。然而,我的分段函数打印同样的东西,它仍然可以正常工作。
【问题讨论】:
-
您应该能够将初始参数、断点、偏移量和斜率都设为数组。这个我没试过。
-
这不是我做的吗?你的意思是单独的数组?为什么有必要 - 我看不出我所做的有什么问题。
-
我添加了另一个可能有助于解释的错误。
-
x 值高于、低于或介于断点值之间的代码导致附加错误。当前逻辑假设 break2 大于 break1,但遗传算法不假设这一点。
标签: python linear-regression piecewise differential-evolution