簡體   English   中英

Scipy最小化,fmin,minimalsq類型問題(設置數組元素與序列),不合適

[英]Scipy minimize, fmin, leastsq type problems (setting array element with sequence), bad fit

我在使用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.

值得注意的是,在傳遞數組列表時,我得到了最小的函數。 不幸的是,它在擬合數據方面表現不佳。 但是,由於我花了很多時間和研究來達到這一點,我將發布如下代碼。 如果有人有興趣看到所有的代碼,我很樂意發布它,如果你可以推薦我上傳一些文件(因為它包括另一個導入的腳本,當然還有樣本數據):

##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,無論你想叫什么)都會運行,但會產生一個瘋狂的答案。 我之前從未使用過非線性優化問題,而且我真的不知道要走向何方。

這是工作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: scipy.optimize.curve_fit

我真的很感激有關如何改進擬合的建議,或者如何定義函數以使optimize.minimize工作,以及哪種方法(Nelder-Mead,Powel,BFGS)可以工作。

另一個要添加的編輯:我得到了Nelder-Mead(optimize.fmin,默認的optimize.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,因為我花了很長時間才發現所有這些。

leastsq不同, fmin只能處理返回標量的錯誤函數,所以如果可能的話,你必須重寫你的錯誤函數,以便它返回一個標量。 這是一個簡單的工作示例。

導入必要的庫

import numpy as np
from scipy.optimize import fmin

定義輔助函數(稍后會看到)

def prob(a, b):
    return (1 + np.exp(b - a))**-1

模擬一些數據

true_ = np.random.normal(size = 100) #parameters we're trying to recover
b = np.random.normal(size = 20)

exp_ = prob(true_[:, None], b) #expected
a_s, b_s = true_.shape[0], b.shape[0]
noise = np.random.uniform(size = (a_s, b_s))
response = (noise > (1 - exp_)).astype(int)

定義我們的錯誤函數(我使用的是lambda但實際上並不推薦這樣做)

# sum of the squared residuals
err_func = lambda a : ((prob(a[:, None], b) - response) ** 2).sum()
result = fmin(err_func, np.zeros_like(true_)) #solve

如果我在錯誤函數定義的末尾刪除.sum() ,我會得到相同的錯誤。

好的,現在我終於知道了答案! 首先,最后一塊,然后回顧一下。 擬合的問題不是curve_fit,leastsq,Nelder_Mead或Powell(我嘗試過的方法)的錯。 它與誤差的相對權重有關。 由於該數據是對數標度,因此高y值附近的擬合誤差非常昂貴,而低y值附近的誤差是不顯着的。 為了糾正這個問題,我通過除以數據的y值使誤差相對,如下所示:

def err_func2(p, x, y, t, t_0):
    return (((carreau(p, x, t, t_0)-y)/y)**2).sum()

現在,每個相對誤差被平方,求和,然后最小化,給出以下擬合(使用powell方法使用optimize.minimize,盡管對於其他方法也應該相同。)

最后,很合適

現在回顧一下這個帖子中的答案:

  • 處理曲線擬合的最簡單方法(或者至少對我而言,最簡單的方法)是將所有數據收集到1D numpy.arrays中。 然后,您可以依靠numpy的陣列廣播來執行所有操作。 這意味着算術運算的處理方式與矢量點積相同。 例如,array_1 = [a,b],array_2 = [c,d],然后是array_1 + array_2 = [a + c,b + d]。 這適用於加法,減法,乘法,除法和冪:array + 1 array_2 = [a c,b ** d]。

  • 對於optimize.leastsq函數,您需要讓目標函數返回一個數組; return result ,其中result是一個數組。 對於optimize.curve_fit,您還返回一個數組。 在這種情況下,傳遞額外的參數(想想其他常量)會有點復雜,但你可以使用嵌套函數來完成它,正如我在pass_data函數中所說明的pass_data

  • 對於optimize.minimize,您需要返回一個標量 - 即一個數字。 我想你也可以返回一系列答案,但我通過將所有數據都放入一維數組來避免這種情況,正如我前面提到的那樣。 要得到這個標量,你可以簡單地對結果進行平方和求和(就像我在err_func2下的這篇文章中err_func2err_func2數據是非常重要的,否則負面錯誤會接管並驅動得到的標量極其負面。

  • 最后,如上所述,當數據越過幾個尺度(10 5,10 4,10 ** 3,等),可能有必要以歸一化的誤差。 我通過將每個誤差除以y值來做到這一點。

那么......我想是的呢? 最后?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM