[英]Curve fit - function failing
曲線是:
import numpy as np
import scipy.stats as sp
from scipy.optimize import curve_fit
from lmfit import minimize, Parameters, Parameter, report_fit#
import xlwings as xw
import os
import pandas as pd
我嘗試從scipy運行一個簡單的曲線擬合:返回
Out[156]:
(array([ 1., 1.]), array([[ inf, inf],
[ inf, inf]]))
好的,所以我認為我需要開始綁定我的參數,這就是求解器的作用。 我使用lmfit來做到這一點:
params = Parameters()
params.add
我嘗試通過更改起始參數來將python推向正確的方向:
或使用curvefit:
我認為問題的一部分是你只有5個觀察值,2個在x
的相同值,並且模型不能完美地表示你的數據。 我還建議嘗試將模型的日志放入數據日志中。 並且,如果您希望n2
為~10,則應將其用作起始值。
任意將min
和max
應用於計算的模型,特別是對於接近數據范圍的值,幾乎沒有意義。 這樣做會阻止擬合方法探索更改參數值對模型函數的影響。
通過對代碼的一些修改以省略第一個數據點(這似乎是拋棄了模型),我發現:
import numpy as np
import scipy.stats as sp
from lmfit import Parameters, minimize, fit_report
import matplotlib.pyplot as plt
x_data = np.array((1e-04,9e-01,9.5835e-01,9.8e-01,9.9e-01,9.9e-01))
y_data = np.array((250e3,1e6,2.5e6,5e6,7.5e6,10e6))
x_data = x_data[1:]
y_data = y_data[1:]
def func(params, x, data, m1=250e3,m2=10e6):
n1 = params['n1'].value
n2 = params['n2'].value
model = n2 + n1*(sp.norm.ppf(x))
return np.log(data) - model
params = Parameters()
params.add('n1', value= 1, min=0.01, max=20)
params.add('n2', value= 10, min=0, max=20)
result = minimize(func, params, args=(x_data[1:-1], y_data[1:-1]))
print(fit_report(result))
n1 = result.params['n1'].value
n2 = result.params['n2'].value
ym = np.exp(n2 + n1*(sp.norm.ppf(x_data)))
plt.plot(x_data, y_data, 'o')
plt.plot(x_data, ym, '-')
plt.legend(['data', 'fit'])
plt.show()
給出報告
[[Fit Statistics]]
# fitting method = leastsq
# function evals = 15
# data points = 3
# variables = 2
chi-square = 0.006
reduced chi-square = 0.006
Akaike info crit = -14.438
Bayesian info crit = -16.241
[[Variables]]
n1: 1.85709072 +/- 0.190473 (10.26%) (init= 1)
n2: 11.5455736 +/- 0.390805 (3.38%) (init= 10)
[[Correlations]] (unreported correlations are < 0.100)
C(n1, n2) = -0.993
當我們提供一個良好的起點時,曲線擬合運行平穩。 我們可以得到一個
sp.norm.ppf(x_data)
和np.log(y_data)
進行線性回歸 或者,如果您希望計算機在沒有“幫助”的情況下找到解決方案
所有四種方法都產生相同的結果,並且優於excel結果。
import numpy as np
import scipy.stats as sp
from scipy.optimize import curve_fit, basinhopping, brute
def func1(x, n1, n2):
return np.clip(np.exp(n2 + n1*(sp.norm.ppf(x))),25e4,10e6)
def func_free(x, n1, n2):
return np.exp(n2 + n1*(sp.norm.ppf(x)))
def sqerr(n12, x, y):
return ((func1(x, *n12) - y)**2).sum()
x_data = np.array((1e-04,9e-01,9.5835e-01,9.8e-01,9.9e-01,9.9e-01))
y_data = np.array((250e3,1e6,2.5e6,5e6,7.5e6,10e6))
# get a good starting point
# either by linear regression
lin = sp.linregress(sp.norm.ppf(x_data), np.log(y_data))
# or by using the free (non-clipped) version of the formula
(n1f, n2f), infof = curve_fit(func_free, x_data, y_data, (1, 1))
# use those on the original problem
(n1, n2), info = curve_fit(func1, x_data, y_data, (lin.slope, lin.intercept))
(n12, n22), info2 = curve_fit(func1, x_data, y_data, (n1f, n2f))
# OR
# use basin hopping
hop = basinhopping(sqerr, (1, 1), minimizer_kwargs=dict(args=(x_data, y_data)), stepsize=10)
# OR
# brute force it
brt = brute(sqerr, ((-100, 100), (-100, 100)), (x_data, y_data), 201, full_output=True)
# all four solutions are essentially the same:
assert np.allclose((n1, n2), (n12, n22))
assert np.allclose((n1, n2), hop.x)
assert np.allclose((n1, n2), brt[0])
# we are actually a bit better than excel
n1excel, n2excel = 1.7925, 11.6771
print('solution', n1, n2)
print('error', ((func1(x_data, n1, n2) - y_data)**2).sum())
print('excel', ((func1(x_data, n1excel, n2excel) - y_data)**2).sum())
輸出:
solution 2.08286042997 11.1397332743
error 3.12796761241e+12
excel 5.80088578059e+12
備注:一個簡單的優化 - 我為了簡單而省略,因為事情還是足夠快 - 本來可以將sp.norm.ppf
從模型函數中拉出來。 這是可能的,因為它不依賴於擬合參數。 因此,當我們的任何求解器調用該函數時,它總是執行完全相同的計算 - sp.norm.ppf(x_data)
- 首先,所以我們不妨預先計算它。
這個觀察也是我們在線性回歸中使用sp.norm.ppf(x_data)
原因。
以下是使用scipy.optimize.curve_fit執行回歸的簡單方法:
import matplotlib.pyplot as plt
import scipy.optimize as opt
import scipy.stats as stats
import numpy as np
% matplotlib inline
# Objective
def model(x, n1, n2):
return np.exp(n2 + n1*(stats.norm.ppf(x)))
# Data
x_samp = np.array((1e-04, 9e-01, 9.5835e-01, 9.8e-01, 9.9e-01, 9.9e-01))
y_samp = np.array((250e3, 1e6, 2.5e6, 5e6 ,7.5e6, 10e6))
x_lin = np.linspace(min(x_samp), max(x_samp), 50) # for fitting
# Regression
p0 = [5, 5] # guessed params
w, cov = opt.curve_fit(model, x_samp, y_samp, p0=p0)
print("Estimated Parameters", w)
y_fit = model(x_lin, *w)
# Visualization
plt.plot(x_samp, y_samp, "ko", label="Data")
plt.plot(x_lin, y_fit, "k--", label="Fit")
plt.title("Curve Fitting")
plt.legend(loc="upper left")
產量
Estimated Parameters [ 2.08285048 11.13975585]
細節
您的數據按原樣繪制,沒有轉換。 如果模型和初始參數 p0
合理地適合您的數據,則最容易執行此類回歸。 當這些項目提供給scipy.optimize.curve_fit
,返回權重元組或優化的估計參數 w
以及協方差矩陣 。 我們可以計算矩陣對角線的一個標准偏差:
p_stdev = np.sqrt(np.diag(cov))
print("Std. Dev. of Params:", p_stdev)
# Std. Dev. of Params: [ 0.42281111 0.95945127]
我們通過再次將這些估計參數提供給模型並繪制擬合線來直觀地評估擬合優度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.