Как передать аргументы другим функциям (как правило, и через scipy)?

Я пытаюсь минимизировать функцию, которая выводит хи-квадрат с помощью 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) Как я могу написать функцию, позволяющую передавать аргументы моей функции chisquareopt?

2) Как я могу определить, оптимизирует ли scipy параметры [mu, sigma, normc], которые дают минимальный хи-квадрат? Как я могу найти эти параметры из оптимизации?

3) Сложно понять, прогрессирую ли я здесь или нет. Я на правильном пути?

РЕДАКТИРОВАТЬ: Если это уместно, у меня есть функция, которая вводит [mu, sigma, normc] и выводит список подсписков, каждый подсписок содержит возможную комбинацию [mu, sigma, normc] (где внешний список охватывает все возможные комбинации параметров в указанных пределах).

2 ответа

Решение

Я несколько упростил вашу проблему, чтобы дать вам представление о вашем вопросе 2).

Во-первых, я жестко запрограммировал вашу гистограмму obslist и количество точек данных N как глобальные переменные (что немного упрощает сигнатуры функций). Во-вторых, я жестко закодировал границы бина в expvalperbinпри условии 9 ячеек с фиксированной шириной 5 и первый бен начинается в 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 гистограмма представляет собой случайную выборку из 1000 точек N(50.5, 7.0) нормальное распределение. Помните, что это мои самые первые строки кода на Python, поэтому, пожалуйста, не судите меня по стилю. Я просто хотел дать вам представление об общей структуре проблемы.

Обычно это 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])

(удалено обсуждение путаницы относительно того, какие параметры минимизированы. См. другой ответ или мою историю изменений)

Другие вопросы по тегам