簡體   English   中英

曲線擬合 - 功能失敗

[英]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,則應將其用作起始值。

任意將minmax應用於計算的模型,特別是對於接近數據范圍的值,幾乎沒有意義。 這樣做會阻止擬合方法探索更改參數值對模型函數的影響。

通過對代碼的一些修改以省略第一個數據點(這似乎是拋棄了模型),我發現:

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)進行線性回歸
  • 或者首先安裝自由(非剪裁)模型

或者,如果您希望計算機在沒有“幫助”的情況下找到解決方案

  • 使用隨機算法,如盆地跳躍(遺憾的是,不是100%自治,我不得不從其默認值增加步長)
  • 蠻力(這需要用戶提供搜索網格)

所有四種方法都產生相同的結果,並且優於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.

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