Python 3.x 如何将参数传递给其他函数(通常是通过scipy传递)?

Python 3.x 如何将参数传递给其他函数(通常是通过scipy传递)?,python-3.x,scipy,arguments,parameter-passing,minimization,Python 3.x,Scipy,Arguments,Parameter Passing,Minimization,我正在尝试通过scipy输出一个函数,并找到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 c

我正在尝试通过scipy输出一个函数,并找到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) 我如何编写一个函数来允许参数传递给我的函数

2) 我如何判断scipy是否会优化给出最小卡方的参数[mu、sigma、Normac]?如何从优化中找到这些参数

3) 很难知道我是否在这里取得了进步。我走对了吗


编辑:如果相关,我有一个函数输入[mu,sigma,Normac]并输出子列表,每个子列表包含[mu,sigma,Normac]的可能组合(其中外部列表包括指定范围内所有可能的参数组合).

通常,这些
scipy
函数会将
args
值元组原封不动地传递给代码。我应该仔细检查代码,但是

minimize(myfunc, x0, args=(y,z))

def myfunc(x, y, z): 
   <do something>
换句话说,它将
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])


(删除了关于将哪些参数最小化的混淆的讨论。请参阅其他答案或我的编辑历史)

我对您的问题进行了一些简化,以便让您了解问题2)

首先,我将柱状图
obslist
和数据点数量
N
硬编码为全局变量(这稍微简化了函数签名)。其次,我在
expvalperbin
中硬编码了箱子边界,假设9个箱子的宽度固定
5
,第一个箱子从
30
开始(因此直方图范围为30到75)

第三,我正在使用
optimize.fmin
(内尔德·米德),而不是
optimize.minimize
。使用
fmin
而不是
minimize
的原因是通过
args=(x,y)
传递附加参数似乎不起作用,因为附加参数从第一次调用起就保持在固定值。这不是你想要的:你想要同时优化
mu
sigma

考虑到这些简化,我们有以下(肯定是非常不和谐的)脚本:

优化已成功终止

当前功能值:2.010966

迭代次数:49

功能评估:95

[50.57590239 7.01857529]


顺便说一句,
obslist
直方图是来自
N(50.5,7.0)
正态分布的1000点随机样本。请记住,这是我的第一个Python代码行,所以请不要以风格来评判我。我只是想给你一个关于问题的一般结构的想法。

那么我应该创建元组(mu、sigma、normc)?或者我应该创建一个所有可能的组合(mu、sigma、normc)的元组吗?我添加了一个简单的示例。我必须考虑更多关于组合的问题。我不理解
mu,sigma,normc
的功能。它们是控制其他变量最小化的参数(binbound),还是要优化的变量(选择最佳组合)?我想选择产生最小卡方误差的mu、sigma、normc的最佳组合。基本上,我计算数据的平均值和stdev来估计每个参数的猜测值。然后将这些参数抛出到函数expvalperbin中,该函数计算期望值。每格的期望值等于每格曲线下的面积;这里,每格定义了积分的界限,每格的期望值被附加到一个列表中。有一个长度相等的单独列表,每个元素都是……的出现次数。。。。。。我的数据点每箱。有了一系列的期望猜测值,这些值对应于每个箱子观察到的不变的多重性,我现在可以为我的卡方算出一个猜测。我想通过改变[mu,sigma,normc]的值来最小化卡方误差,这很困难,因为它们会影响分布函数,而分布函数是在期望值的二元边界上集成的(因此我的函数的结构)。我的柱状图单元被定义为单元边界列表,我希望通过卡方检验来覆盖该列表的最佳拟合。在函数expvalperbin中,“args=(mu,sigma))[0]*N”做什么?我猜它复制了一个(mu,sigma)N次的元组,但是下标[0]让我相信我没有看到完整的图片(类似于'chisquareopt'中的args)?至于不是pythonic,我愿意接受建议。这和你的
ans.append(quad(gauss,binbound[index],binbound[index+1])[0])一样。
。但是我也将
mu
lambda
传递给
gauss
函数。最后,要从概率中得到预期的计数,你必须乘以观察的总数(我已经告诉过你了)。啊,我现在看到了!谢谢你的帮助。在你的帮助下,我能够优化我的参数。但出于好奇,我在你的指导下阅读了这些文件,感到困惑。您是否能够仅从文档中了解结构,如果是,如何了解?我希望能够使我的理解适应未来的其他模块文档……正如我在你的另一篇文章中所说的,我对Python/scipy一无所知。因此,
args=(x)
问题有点出乎意料。但是你需要的参数对我来说总是很清楚的(你可以通过重新阅读我的评论来检查)。我想这不是关于Python/scipy的,而是关于没有做过(思考过)类似的事情
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])
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)