我正在尝试minimize一个通过scipy输出chi-square的函数,并找到最适合高斯叠加的mu,sigma,normc。
from math import exp
from math import pi
from scipy.integrate import quad
from scipy.optimize import minimize
from scipy.stats import chisquare
import numpy as np
# guess intitial values for minimized chi-square
mu, sigma = np.mean(mydata), np.std(mydata) # mydata is my data points
normc = 1/(sigma * (2*pi)**(1/2))
gauss = lambda x: normc * exp( (-1) * (x - mu)**2 / ( 2 * (sigma **2) ) ) # Gaussian Distribution
# assume I have pre-defined bin-boundaries as a list called binbound
def expvalperbin(binbound,mu,sigma,normc):
# calculates expectation value per bin
ans = []
for index in range(len(binbound)):
if index != len(binbound)-1:
ans.append( quad( gauss, binbound[index], binbound[index+1])[0] )
return ans
expvalguess = expvalperbin(binbound,mu,sig,normc)
obsval = countperbin(binbound,mydata)
arglist = [mu,sig,norm]
def chisquareopt(obslist,explist):
return chisquare(obslist,explist)[0]
chisquareguess = chisquareopt((obsval,expvalguess), expvalguess, args=arglist)
result = minimize( chisquareopt(obsval,expvalguess), chisquareguess )
print(result)
运行此代码会向我提供此错误:
TypeError: chisquareopt() got an unexpected keyword argument 'args'
我有几个问题:
1)如何编写一个函数来允许将参数传递给我的函数chisquareopt?
2)我如何判断scipy是否会优化给出最小卡方的参数[mu,sigma,normc]?我怎样才能从优化中找到这些参数?
3)很难知道我是否在这里取得进展。我是在正确的轨道上吗?
编辑:如果它是相关的,我有一个输入[mu,sigma,normc]的函数并输出一个子列表列表,每个子列表包含[mu,sigma,normc]的可能组合(其中外部列表涵盖指定范围内所有可能的参数组合。)答案 0 :(得分:3)
通常,这些scipy
函数会将args
元组值传递给您的代码。我应该仔细检查代码,但是用
minimize(myfunc, x0, args=(y,z))
def myfunc(x, y, z):
<do something>
minimize
获取变量x
的当前值(标量或数组,具体取决于x0
的外观),以及args
参数和构造
args = tuple(x) + args
myfunc(*args)
换句话说,它将args
元组与迭代变量连接起来并将其传递给您的函数。因此,任何中间函数定义都需要使用该模式。
为了说明,定义一个采用通用args元组的函数。
In [665]: from scipy.optimize import minimize
In [666]: def myfunc(*args):
...: print(args)
...: return np.abs(args[0])**2
...:
In [667]: myfunc(1,2,3)
(1, 2, 3)
Out[667]: 1
In [668]: myfunc(2,2,3)
(2, 2, 3)
Out[668]: 4
In [669]: minimize(myfunc, 10, args=(2,3))
(array([ 10.]), 2, 3)
(array([ 10.00000001]), 2, 3)
(array([ 10.]), 2, 3)
(array([ 8.99]), 2, 3)
....
(array([-0.00000003]), 2, 3)
Out[669]:
fun: 1.7161984122524196e-15
hess_inv: array([[ 0.50000001]])
jac: array([-0.00000007])
message: 'Optimization terminated successfully.'
nfev: 15
nit: 4
njev: 5
status: 0
success: True
x: array([-0.00000004])
(删除了关于哪些参数被最小化的混淆的讨论。请参阅其他答案或我的编辑历史)
答案 1 :(得分:3)
我已经简化了你的问题,让你对你的问题有所了解2)。
首先,我将您的直方图obslist
和数据点数N
硬编码为全局变量(这简化了函数签名)。其次我在expvalperbin
中对bin边界进行了硬编码,假设有9个具有固定宽度5
的bin,第一个bin从30
开始(因此直方图的范围是30到75) )。
第三,我使用optimize.fmin
(Nelder-Mead)代替optimize.minimize
。使用fmin
代替minimize
的原因是,通过args=(x,y)
传递其他参数似乎无法在附加参数保持固定值的意义上起作用从第一次调用开始。这不是您想要的:您希望同时优化mu
和sigma
。
鉴于这些简化,我们有以下(当然非常非语音)脚本:
from math import exp
from math import pi
from scipy.integrate import quad
from scipy.optimize import fmin
from scipy.stats import chisquare
obslist = [12, 51, 144, 268, 264, 166, 75, 18, 2] # histogram, 1000 observations
N = 1000 # no. of data points
def gauss(x, mu, sigma):
return 1/(sigma * (2*pi)**(1/2)) * exp( (-1) * (x - mu)**2 / ( 2 * (sigma **2) ) )
def expvalperbin(mu, sigma):
e = []
# hard-coded bin boundaries
for i in range(30, 75, 5):
e.append(quad(gauss, i, i + 5, args=(mu, sigma))[0] * N)
return e
def chisquareopt(args):
# args[0] = mu
# args[1] = sigma
return chisquare(obslist, expvalperbin(args[0], args[1]))[0]
# initial guesses
initial_mu = 35.5
initial_sigma = 14
result = fmin(chisquareopt, [initial_mu, initial_sigma])
print(result)
优化已成功终止。
当前功能值:2.010966
迭代:49
功能评估:95
[50.57590239 7.01857529]
顺便说一下,obslist
直方图是来自N(50.5, 7.0)
正态分布的1000点随机样本。请记住,这些是我的第一个Python代码行,所以请不要在风格上判断我。我只是想让你了解问题的一般结构。