Saya telah mencari penyesuaian kurva Python dengan kendala. Salah satu opsinya adalah menggunakan modul lmfit dan opsi lainnya adalah menggunakan < a href="https://stackoverflow.com/questions/16541171/how-do-i-put-a-constraint-on-scipy-curve-fit">penalti untuk menegakkan batasan. Saya memiliki kode berikut di mana saya mencoba untuk menerapkan a+b=3.6 sebagai kendala. Dengan kata lain, y=3.6 ketika x=1 dan x selalu >=1 dalam kasus saya.

import numpy as np
import scipy.optimize as sio
def func(x, a, b, c):
    return a+b*x**c

x = [1, 2, 4, 8, 16]
y = [3.6, 3.96, 4.31, 5.217, 6.842]
lb = np.ones(3, dtype=float)
ub = np.ones(3, dtype=float)*10.
popt, pcov = sio.curve_fit(func, x, y)
print(popt)

Idealnya, saya ingin menggunakan pendekatan lmfit dan menghabiskan banyak waktu untuk mencoba memahami contoh tetapi tidak berhasil. Adakah yang bisa membantu dengan contoh?

1
SKPS 18 Mei 2021, 04:45

1 menjawab

Jawaban Terbaik

Jika saya memahami pertanyaan Anda dengan benar, Anda ingin memodelkan beberapa data dengan

def func(x, a, b, c):
    return a+b*x**c

Dan untuk kumpulan data tertentu Anda ingin menerapkan batasan a+b=3.6. Anda bisa, cukup "menghubungkan itu", mengubah fungsinya menjadi

def func2(x, b, c):
    a = 3.6 - b
    return a+b*x**c

Dan sekarang Anda memiliki fungsi model dengan hanya dua variabel: b, dan c.

Itu tidak akan sangat fleksibel tetapi akan berhasil.

Menggunakan lmfit mengembalikan sebagian dari fleksibilitas itu. Untuk melakukan kecocokan yang benar-benar tidak dibatasi, Anda akan mengatakan

from lmfit import Model

mymodel = Model(func)
params = mymodel.make_params(a=2, b=1.6, c=0.5)
result = mymodel.fit(y, params,  x=x)

(Sebagai tambahan: scipy.optimize.curve_fit mengizinkan Anda untuk tidak menentukan nilai awal untuk parameter dan secara implisit menetapkannya ke 1 tanpa memberi tahu Anda. Ini adalah kesalahan fitur yang mengerikan - selalu berikan nilai awal).

Jika Anda ingin menerapkan batasan a+b=3.6, Anda dapat melakukannya

params['a'].expr = '3.6-b'

result2 = mymodel.fit(y, params, x=x)
print(result2.fit_report())

Ketika saya melakukannya dengan data yang Anda berikan, ini dicetak (perhatikan bahwa ini melaporkan 2 variabel, bukan 3):

[[Model]]
    Model(func)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 34
    # data points      = 5
    # variables        = 2
    chi-square         = 0.01066525
    reduced chi-square = 0.00355508
    Akaike info crit   = -26.7510142
    Bayesian info crit = -27.5321384
[[Variables]]
    a:  3.28044833 +/- 0.04900625 (1.49%) == '3.6-b'
    b:  0.31955167 +/- 0.04900626 (15.34%) (init = 1.6)
    c:  0.86901253 +/- 0.05281279 (6.08%) (init = 0.5)
[[Correlations]] (unreported correlations are < 0.100)
    C(b, c) = -0.994

Kode Anda mengisyaratkan penggunaan (tetapi tidak benar-benar menggunakan) batas atas dan bawah untuk nilai parameter. Itu juga dimungkinkan dengan lmfit, seperti dengan

params['b'].min = 1
params['b'].min = 10

Dan seterusnya. Saya tidak yakin Anda membutuhkannya di sini, dan akan berhati-hati agar tidak mencoba menetapkan batas terlalu ketat.

2
M Newville 18 Mei 2021, 02:59