我的问题很快,但我提供了大量的代码来更好地说明我的问题,因为我还没有从阅读相关帖子中理解答案。
下面的代码是选择属于args列表的优化参数。 args列表应该是单个条目like x0 on scipy docs。我希望找到正确的args组合以最好地拟合数据。 scipy优化模块应该使我的args的值波动,以找到最小化我的错误的组合。但是,我无法将args从一个函数传递到另一个函数。
有时我会设置*
或**
,但我的成功率更高,而不是命中率。我想知道如何将args从一个函数传递到另一个函数,同时允许它们更改值以便找到它们的优化值。 (优化值可减少误差,如下所述)。我有一些函数作为其他函数的输入,在这里缺少一个关键概念。这样的事情需要kwargs吗?如果args是一个元组,它们是否仍然可以更改值以查找优化参数?我知道这里有一些类似的问题,但我还没有能够用这些资源来解决这个问题。
下面解释了代码(导入后)。
import numpy as np
import random
import matplotlib.pyplot as plt
from math import exp
from math import log
from math import pi
from scipy.integrate import quad ## integrate f(x)dx from x_i to x_i+1
from scipy.stats import norm
from scipy.stats import chisquare
from scipy.optimize import basinhopping
from scipy.stats import binned_statistic as bstat
我生成了1000个数据点的随机高斯分布样本,平均μ= 48,标准差sigma = 7.我可以对数据进行直方图,我的目标是找到参数mu,sigma和normc(缩放因子或归一化常数),它们最适合样本数据的直方图。有许多误差分析方法,但出于我的目的,最佳拟合被确定为最小化卡方的拟合(在下面进一步描述)。我知道代码很长(甚至太长),但我的问题需要一些设置。
## generate data sample
a, b = 48, 7 ## mu, sigma
randg = []
for index in range( 1000 ):
randg.append( random.gauss(a,b) )
data = sorted( randg )
small = min( data )
big = max( data )
domain = np.linspace(small,big,3000) ## for fitted plot overlay on histogram of data
然后我为直方图组织了我的箱子。
numbins = 30 ## number of bins
def binbounder( small , big , numbins ):
## generates list of bound bins for histogram ++ bincount
binwide = ( big - small ) / numbins ## binwidth
binleft = [] ## left edges of bins
for index in range( numbins ):
binleft.append( small + index * binwide )
binbound = [val for val in binleft]
binbound.append( big ) ## all bin edges
return binbound
binborders = binbounder( small , big , numbins )
## useful if one performs plt.hist(data, bins = binborders, ...)
def binmidder( small , big , numbins ):
## all midtpts of bins
## for x-ticks on histogram
## useful to visualize over/under -estimate of error
binbound = binbounder( small , big , numbins )
binwide = ( big - small ) / numbins
binmiddles = []
for index in range( len( binbound ) - 1 ):
binmiddles.append( binwide/2 + index * binwide )
return binmiddles
binmids = binmidder( small , big , numbins )
要进行卡方分析,必须输入每箱的期望值(E_i)和每个箱的观测值的乘数(O_i)和它们的差的平方的output the sum over all the bins超过每箱的期望值。
def countsperbin( xdata , args = [ small , big , numbins ]):
## calculates multiplicity of observed values per bin
binborders = binbounder( small , big , numbins )
binmids = binmidder( small , big , numbins )
values = sorted( xdata ) ## function(xdata) ~ f(x)
bincount = []
for jndex in range( len( binborders ) ):
if jndex != len( binborders ) - 1:
summ = 0
for val in values:
if val > binborders[ jndex ] and val <= binborders[ jndex + 1 ]:
summ += 1
bincount.append( summ )
if jndex == len( binborders ) - 1:
pass
return bincount
obsperbin = countsperbin( binborders , data ) ## multiplicity of observed values per bin
计算和最小化Chi Squared所需的每个bin的每个期望值被定义为从x_i = left binedge到x_i + 1 = right binedge的分布函数的积分。
我想对我的优化参数进行合理的初始猜测,因为这些可以让我对最小化的Chi Squared进行合理的猜测。我选择mu,sigma和normc接近但不等于它们的真值,以便我可以测试最小化是否有效。
def maxbin( perbin ):
## perbin is a list of observed data per bin
## returns largest multiplicity of observed values with index
## useful to help guess scaling factor "normc" (outside exponential in GaussDistrib)
for index, maxval in enumerate( perbin ):
if maxval == max( perbin ):
optindex = index
return optindex, perbin[ optindex ]
mu, sigma, normc = np.mean( data ) + 30, np.std( data ) + 20, maxbin( obsperbin )
由于我们正在整合f(x)dx,因此数据点(或xdata)与此无关。
def GaussDistrib( xdata , args = [ mu , sigma , normc ] ): ## G(x)
return normc * exp( (-1) * (xdata - mu)**2 / (2 * sigma**2) )
def expectperbin( args ):
## calculates expectation values per bin
## needed with observation values per bin for ChiSquared
## expectation value of single bin is equal to area under Gaussian curve from left binedge to right binedge
## area under curve for ith bin = integral G(x)dx from x_i (left edge) to x_i+1 (right edge)
ans = []
for index in range(len(binborders)-1): # ith index does not exist for rightmost boundary
ans.append( quad( GaussDistrib , binborders[ index ] , binborders[ index + 1 ], args = [ mu , sigma , normc ])[0])
return ans
我定义的函数chisq
从scipy模块调用chisquare
以返回结果。
def chisq( args ):
## args[0] = mu
## args[1] = sigma
## args[2] = normc
## last subscript [0] gives chi-squared value, [1] gives 0 ≤ p-value ≤ 1
## can also minimize negative p-value to find best fitting chi square
return chisquare( obsperbin , expectperbin( args[0] , args[1] , args[2] ))[0]
我不知道如何,但我想在我的系统上设置约束。具体而言,分箱数据高度列表的最大值必须大于零(由于分辨后保留的指数项,因此必须为Chi Square)。
def miniz( chisq , chisqguess , niter = 200 ):
minimizer = basinhopping( chisq , chisqguess , niter = 200 )
## Minimization methods available via https://docs.scipy.org/doc/scipy-0.18.1/reference/optimize.html
return minimizer
expperbin = expectperbin( args = [mu , sigma , normc] )
# chisqmin = chisquare( obsperbin , expperbin )[0]
# chisqmin = result.fun
""" OPTIMIZATION """
print("")
print("initial guess of optimal parameters")
initial_mu, initial_sigma, initial_normc = np.mean(data)+30 , np.std(data)+20 , maxbin( (obsperbin) )
## check optimized result against: mu = 48, sigma = 7 (via random number generator for Gaussian Distribution)
chisqguess = chisquare( obsperbin , expectperbin( args[0] , args[1] , args[2] ))[0]
## initial guess for optimization
result = miniz( chisqguess, args = [mu, sigma, normc] )
print(result)
print("")
最小化的目的是找到最佳拟合的优化参数。
optmu , optsigma , optnormc = result.x[0], abs(result.x[1]), result.x[2]
chisqcheck = chisquare(obsperbin, expperbin)
chisqmin = result.fun
print("chisqmin -- ",chisqmin," ",chisqcheck," -- check chi sq")
print("""
""")
## CHECK
checkbins = bstat(xdata, xdata, statistic = 'sum', bins = binborders) ## via SCIPY (imports)
binsum = checkbins[0]
binedge = checkbins[1]
binborderindex = checkbins[2]
print("binsum",binsum)
print("")
print("binedge",binedge)
print("")
print("binborderindex",binborderindex)
# Am I doing this part right?
tl; dr:我想要result
,它调用函数minimiz
,调用scipy模块以使用猜测值最小化Chi Squared。 Chi Squared和猜测值各自调用其他函数等。如何通过正确的方式传递我的args?
答案 0 :(得分:3)
您可以访问optimize.basinhopping
返回的OptimizeResult中的所有信息。
我抽象出随机样本的生成,并将函数的数量减少到运行优化所需的5个函数。
参数传递中唯一“棘手”的部分是将参数mu
和sigma
传递给{{里面的 GaussDistrib 函数1}}调用,但这在quad doc中很容易解释。除此之外,我没有看到参数传递的真正问题。
长时间使用quad
是错误的。你没有从高斯那里得到正确的值(当2就足够时,不需要改变3个独立的参数)。此外,要获得卡方的正确值,您必须将高斯的概率乘以样本计数(您将normc
箱中的绝对计数与高斯下的概率进行比较 - 这显然是错误的)。
obsperbin
最初猜测的chisquare:3772.70822797
优化后的chisquare:26.351284911784447
mu,sigma优化后:48.2701027439,7.046156286
顺便说一下,basinhopping对于这类问题来说太过分了。我会留在fmin(Nelder-Mead)。