Python - подгонка кривой более сложной функции

Я хочу найти уравнение кривой наилучшего соответствия следующего графика: введите здесь описание изображения

Что имеет уравнение в виде:

введите здесь описание изображения

Я попытался найти примеры подгонки кривой с помощью numpy здесь и здесь, но они все только показывают, как построить только экспоненциальную или только синусоидальную, но я хотел бы построить график, сочетающий две функции.

Как бы я это сделал?


person George Tian    schedule 20.10.2018    source источник
comment
Вы можете создать свою собственную функцию со своим уравнением, а затем использовать curve_fit из SciPy. Здесь можно увидеть несколько примеров.   -  person Sheldore    schedule 20.10.2018


Ответы (2)


Вот один из подходов, который может оказаться полезным. Здесь используется lmfit (http://lmfit.github.io/lmfit-py/) , который обеспечивает высокоуровневый подход к подгонке кривой:

import numpy as np
import matplotlib.pyplot as plt

from lmfit import Model

def decay_cosine(t, amp, beta, omega, phi):
    """model data as decaying cosine wave"""
    return amp * np.exp(-beta*t)* np.cos(omega*t + phi)

# create fake data to be fitted
t = np.linspace(0, 5, 101)
y = decay_cosine(t, 1.4, 0.9, 7.2, 0.23) + np.random.normal(size=len(t), scale=0.05)

# build model from decay_cosine
mod = Model(decay_cosine)

# create parameters, giving initial values
params = mod.make_params(amp=2.0, beta=0.5, omega=5, phi=0)

# you can place bounds on parameters:
params['phi'].max = np.pi/2
params['phi'].min = -np.pi/2
params['amp'].min = 0

# fit data to model

result = mod.fit(y, params, t=t)

# print out fit results
print(result.fit_report())

# plot data with best fit
plt.plot(t, y, 'bo', label='data')
plt.plot(t, result.best_fit, 'r')
plt.show()

Это распечатает такой отчет:

[[Model]]
    Model(decay_cosine)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 46
    # data points      = 101
    # variables        = 4
    chi-square         = 0.25540159
    reduced chi-square = 0.00263301
    Akaike info crit   = -595.983903
    Bayesian info crit = -585.523421
[[Variables]]
    amp:    1.38812335 +/- 0.03034640 (2.19%) (init = 2)
    beta:   0.90760648 +/- 0.02820705 (3.11%) (init = 0.5)
    omega:  7.16579292 +/- 0.02891827 (0.40%) (init = 5)
    phi:    0.26249321 +/- 0.02225816 (8.48%) (init = 0)
[[Correlations]] (unreported correlations are < 0.100)
    C(omega, phi)  = -0.713
    C(amp, beta)   =  0.695
    C(amp, phi)    =  0.253
    C(amp, omega)  = -0.183
    C(beta, phi)   =  0.178
    C(beta, omega) = -0.128

и создайте такой сюжет:

введите здесь описание изображения

person M Newville    schedule 24.10.2018
comment
Спасибо, это как раз то, что я искал. Однако ошибка ImportError: cannot import name 'Model' from 'lmfit' выскочила, когда я попытался запустить точную копию вашего кода. Вы знаете, в чем может быть дело? Я установил lmfit v. 0.9.11 через pip - person George Tian; 25.10.2018
comment
Хм, похоже, что он не был установлен правильно. Можете ли вы сделать import lmfit в сеансе Python? Вы можете проверить, где на самом деле был установлен модуль. - person M Newville; 26.10.2018
comment
О, оказывается, я назвал свой файл lmfit.py, и это вызвало ошибку. Переименование файла помогло. - person George Tian; 26.10.2018

Вот довольно простой пример использования curve_fit и leastsq из scipy.optimize.

<сильный>1. Установка значений параметров, модельных и экспериментальных данных.

import numpy as np
import scipy.optimize
import matplotlib.pyplot as plt

np.random.seed(0)  # choosing seed for reproducibility

# ==== theoretical parameter values ====
x0 = 1
beta = .5
omega = 2*np.pi
phi = 0
params = x0, beta, omega, phi

# ==== model ====
def decay_cosine(t, x0, beta, omega, phi):
    x = x0 * np.exp(-beta*t_data) * np.cos(omega*t_data + phi)
    return x

# ==== generating experimental data ====
t_data = np.linspace(0, 5, num=80)
noise = .05 * np.random.randn(t_data.size)
x_data = decay_cosine(t_data, *params) + noise

<сильный>2. Подгонка.

# ==== fitting using curve_fit ====
params_cf, _ = scipy.optimize.curve_fit(decay_cosine, t_data, x_data)

# ==== fitting using leastsq ====
def residuals(args, t, x):
    return x - decay_cosine(t, *args)

x0 = np.ones(len(params))  # initializing all params at one
params_lsq, _ = scipy.optimize.leastsq(residuals, x0, args=(t_data, x_data))

print(params_cf)
print(params_lsq)
array([ 1.04938794,  0.53877389,  6.30375113, -0.01850761])
array([ 1.04938796,  0.53877389,  6.30375103, -0.01850744])

<сильный>3. График.

plt.plot(t_data, x_data, '.', label='exp data')
plt.plot(t_data, decay_cosine(t_data, *params_cf), label='curve_fit')
plt.plot(t_data, decay_cosine(t_data, *params_lsq), '--', label='leastsq')
plt.legend()
plt.grid(True)
plt.show()

введите здесь описание изображения

person Alfredo    schedule 18.08.2020