我在使用 scipy.optimize.fmin 和 scipy.optimize.minimize 函数时遇到问题。我检查并确认传递给函数的所有参数都是 numpy.array 类型,以及错误函数的返回值。此外,carreau 函数返回一个标量值。
一些额外参数(例如大小)的原因是:我需要使用给定模型(Carreau)拟合数据。数据是在不同的温度下获取的,并用偏移因子(也由模型拟合)进行了校正,我最终得到了几组数据,它们都应该用于计算相同的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.
值得注意的是,我在传递数组列表时让 leastsq 函数正常工作。不幸的是,它在拟合数据方面做得很差。但是,由于我花了很多时间和研究来达到这一点,我将发布代码如下。如果有人有兴趣查看所有代码,我很乐意发布它,如果您可以推荐我上传一些文件(因为它包括另一个导入的脚本,当然还有示例数据):
##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 分。
后期编辑:我现在已经让 optimize.curvefit 和 optimize.leastsq 工作(可能不太巧合地给出相同的答案),但曲线很糟糕。我一直在试图弄清楚optimize.minimize,但这有点让人头疼。单纯形(fmin,Nelder_Mead,无论你想怎么称呼它)都会运行,但会产生一个疯狂的答案。我以前从未处理过非线性优化问题,而且我真的不知道该往哪个方向发展。
这是工作曲线拟合代码:
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)可能起作用的建议。
另一个要添加的编辑:我让 Nelder-Mead(optimize.fmin,和默认的 optimize.minimize)函数工作 - 我将在下面包含修改后的错误函数。之前,我只是简单地对结果数组求和并返回它。这导致了极负的值(显然,因为函数的目标是最小化)。在求和之前对结果求平方解决了这个问题。请注意,正如 JaminSore 所建议的那样,我还完全更改了函数以利用 numpy 的数组广播(感谢 Jamin!)
def err_func2(p, x, y, t, t_0):
return ((carreau(p, x, t, t_0)-y)**2).sum()
不幸的是,Nelder-Mead 函数给出了与 minimumsq 和 curve_fit 相同的结果。您可以在上图中看到它不是最佳拟合;事实上,在这一点上,Microsoft Excel 的求解器功能在数据上做得更好。
至少,我希望这个线程对将来 scipy.optimize 的初学者有用,因为我花了很长时间才发现所有这些。