我在使用scipy.optimize.fmin和scipy.optimize.minimize函数时遇到了麻烦 . 我检查并确认传递给函数的所有参数都是numpy.array类型,以及错误函数的返回值 . 此外,carreau函数返回标量值 .
一些额外参数(例如大小)的原因是:我需要使用给定模型(Carreau)来拟合数据 . 数据是在不同的温度下获得的,这些温度用移位因子(也由模型拟合)校正,我最终得到几组数据,这些数据都应该用于计算 same 4常数(参数p) .
我读到我无法将fmin函数传递给数组列表,因此我不得不将所有数据连接到x_data_lin中,使用size参数跟踪不同的集合 . t保持不同的测试温度,而t_0是保持参考温度的单元件阵列 .
我是肯定的(三重检查)传递给函数的所有参数以及结果都是一维数组 . 这是除此之外的代码:
import numpy as np
import scipy.optimize
from scipy.optimize import fmin as simplex
def err_func2(p, x, y, t, t_0, size):
result = array([])
temp = 0
for i in range(0, int(len(size)-1)):
for j in range(int(temp), int(temp+size[i])):
result = np.append(result, (carreau(p, x[j], t[i], t_0[0])-y[i]))
temp += size[i]
return result
p1 = simplex(err_func2, initial_guess,
args=(x_data_lin, y_data_lin, t_list, t_0, size), full_output=0)
这是错误:
Traceback (most recent call last):
File "C:\Python27\Scripts\projects\Carreau - WLF\carreau_model_fit.py", line 146, in <module>
main()
File "C:\Python27\Scripts\projects\Carreau - WLF\carreau_model_fit.py", line 105, in main
args=(x_data_lin, y_data_lin, t_list, t_0, size), full_output=0)
File "C:\Python27\lib\site-packages\scipy\optimize\optimize.py", line 351, in fmin
res = _minimize_neldermead(func, x0, args, callback=callback, **opts)
File "C:\Python27\lib\site-packages\scipy\optimize\optimize.py", line 415, in _minimize_neldermead
fsim[0] = func(x0)
ValueError: setting an array element with a sequence.
值得注意的是,在传递数组列表时,我得到了最小的函数 . 不幸的是,它在拟合数据方面表现不佳 . 但是,由于我花了很多时间和研究来达到这一点,我将发布如下代码 . 如果有人有兴趣看到所有的代码,我很乐意发布它,如果你可以推荐我上传一些文件(因为它包括另一个导入的脚本,当然还有样本数据):
##def error_function(p, x, y, t, t_0):
## result = array([])
## for index in range(len(x)):
## result = np.append(result,(carreau(p, x[index],
## t[index], t_0) - y[index]))
## return result
## p1, success = scipy.optimize.leastsq(error_function, initial_guess,
## args=(x_list, y_list, t_list, t_0),
## maxfev=10000)
:(我打算用最小的拟合发布图表的图表数据,但我没有必要的10分 .
Late Edit: 我现在已经使optimize.curvefit和optimize.leastsq工作了(这可能不是巧合地给出相同的答案),但曲线很糟糕 . 我've been trying to figure out optimize.minimize, but it'有点头疼 . 单纯形式(fmin,Nelder_Mead,无论你想叫什么)都会运行,但会产生一个疯狂的答案 . 我真的知道要走向何方 .
这是工作curve_fit代码:
def temp_shift(t_s, t, t_0):
""" This function calculates the a_t temperature shift factor for polymer
viscosity curves. Variable is the standard temperature, t_s
"""
C_1 = 8.86
C_2 = 101.6
return(np.exp(
(C_1*(t_0-t_s) / (C_2+(t_0-t_s))) - (C_1*(t-t_s) / (C_2 + (t-t_s)))
))
def pass_data(t, t_0):
def carreau_2(x, p0, p1, p2, p3):
visc_0 = p0
m = p1
n = p2
t_s = p3
a_T = temp_shift(p3, t, t_0)
return (visc_0 * a_T / (1 + m * x * a_T)**n)
return carreau_2
initial_guess = array([20000, 3, 0.94, -20])
p1, conv = scipy.optimize.curve_fit(pass_data(t_all, t_0), x_data_lin,
y_data_lin, initial_guess)
这是一些示例数据:
x_data_lin = array([0.01998, 0.04304, 0.2004, 0.43160, 0.92870, 2.0000, 4.30900,
9.28500, 15.51954, 21.94936, 37.52960, 90.41786, 204.35230,
331.58495, 811.92250, 1694.55309, 3464.27648, 8826.65738,
14008.00242])
y_data_lin = array([13520.00000, 13740.00000, 12540.00000, 9384.00000, 5201,
3232.00000, 2094.00000, 1484.00000, 999.00000, 1162.05088
942.56946, 705.62489, 429.47341, 254.15136, 185.22916,
122.07113, 76.46324, 47.85064, 25.74315, 18.84875])
t_all = array([190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
190, 190, 190, 190, 190, 190, 190])
t_0 = 80
这是curve_fit结果的图片(现在我有10分可以发帖!) . 注意,绘制了3条曲线,因为我使用3组数据来优化曲线,在3个不同的温度下 . 聚合物具有剪切比 - 粘度关系保持不变的特性,只是移动了温度因子a_T:
我真的很感激有关如何改进拟合的建议,或者如何定义函数以使optimize.minimize工作,以及哪种方法(Nelder-Mead,Powel,BFGS)可以工作 .
Another edit to add: 我得到了Nelder-Mead(optimize.fmin,默认的optimize.minimize)函数 - 我'll include the revised error function below. Before, I simply summed the result array and returned it. This led to extremely negative values (obviously, since the function'的目标是 minimize ) . 在求和之前平方结果解决了这个问题 . 请注意,我也完全改变了函数以利用numpy的数组广播,正如JaminSore所建议的那样(感谢Jamin!)
def err_func2(p, x, y, t, t_0):
return ((carreau(p, x, t, t_0)-y)**2).sum()
不幸的是,Nelder-Mead函数给出了与leastsq和curve_fit相同的结果 . 您可以在上图中看到它不是最佳拟合;事实上,在这一点上,Microsoft Excel的求解器功能在数据上做得更好 .
至少,我希望这个帖子对初学者来说有用,可以在将来进行scipy.optimize,因为我花了很长时间才发现所有这些 .
2 回答
与
leastsq
不同,fmin
只能处理返回标量的错误函数,因此如果可能,您必须重写错误函数,以便返回标量 . 这是一个简单的工作示例 .导入必要的库
定义辅助函数(稍后会看到)
模拟一些数据
定义我们的错误函数(我正在使用
lambda
s,但在实践中不建议这样做)如果我在错误函数定义结束时删除
.sum()
,我会得到相同的错误 .好的,现在我终于知道了答案!首先,最后一块,然后回顾一下 . 拟合的问题不是curve_fit,leastsq,Nelder_Mead或Powell(我尝试过的方法)的错 . 它与误差的相对权重有关 . 由于该数据是对数标度,因此高y值附近的拟合误差非常昂贵,而低y值附近的误差是不显着的 . 纠正这个,我通过除以数据的y值使误差相对,如下:
现在,每个相对误差被平方,求和,然后最小化,给出以下拟合(使用powell方法使用optimize.minimize,尽管对于其他方法也应该相同 . )
现在回顾一下这个帖子中的答案:
处理曲线拟合的最简单方法(或者至少对我而言,最简单的方法)是将所有数据收集到1D numpy.arrays中 . 然后,您可以依靠numpy的阵列广播来执行所有操作 . 这意味着算术运算的处理方式与矢量点积相同 . 例如,array_1 = [a,b],array_2 = [c,d],然后是array_1 array_2 = [a c,b d] . 这适用于加法,减法,乘法,除法和幂:数组1 **array_2 = [a** c,b ** d] .
对于optimize.leastsq函数,需要让目标函数返回一个数组;即
return result
,其中result是一个数组 . 对于optimize.curve_fit,您还返回一个数组 . 在这种情况下,传递额外的参数(想想其他常量)会有点复杂,但你可以使用嵌套函数来完成它,正如我在pass_data
函数中所演示的那样 .对于optimize.minimize,您需要返回一个标量 - 即一个数字 . 我想你也可以返回一系列答案,但我通过将所有数据都放入一维数组来避免这种情况,正如我前面提到的那样 . 要得到这个标量,你可以简单地对结果进行平方和求和(就像我在
err_func2
中写的那样) balancer 数据是非常重要的,否则负面错误会接管并驱动得到的标量极其负面 .最后,如上所述,当您的数据跨越多个等级(10 5, 10 4,10 ** 3等)时,可能需要对错误进行标准化 . 我通过将每个误差除以y值来做到这一点 .
那么......我想是的呢?最后?