Мой вопрос быстрый, но я предоставил здоровенный фрагмент кода, чтобы лучше проиллюстрировать мою проблему, поскольку я не понял ответа, прочитав соответствующие сообщения.
Приведенный ниже код предназначен для выбора оптимизированных параметров, которые являются частью списка аргументов. Список аргументов должен быть одной записью как x0 в scipy docs < / а>. Я надеюсь найти правильную комбинацию аргументов, которая наилучшим образом соответствует данным. Модули scipy optimize должны колебать значения моих аргументов, чтобы найти комбинацию, которая минимизирует мою ошибку в наибольшей степени. Но у меня возникают проблемы с передачей аргументов из одной функции в другую.
Иногда я ставлю *
или **
, но мой успех - это скорее промах, чем попадание. Я хочу знать, как передавать аргументы из одной функции в другую, позволяя им изменять значение, чтобы найти их оптимизированное значение. (Оптимизированное значение уменьшает ошибку, как описано ниже). У меня есть несколько функций, которые служат входными данными для других функций, и здесь мне не хватает ключевой концепции. Нужны ли для чего-то кварги? Если аргументы являются кортежем, могут ли они по-прежнему изменять значение для поиска оптимизированных параметров? Я знаю, что здесь, на SO, задавались несколько схожие вопросы, но я еще не смог понять это с помощью этих ресурсов.
Код поясняется ниже (после импорта).
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 точек данных со средним mu = 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) и вывести сумму по всем ячейкам квадрата их разницы по ожидаемому значению на ячейку.
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
Каждое ожидаемое значение для каждого бина, которое необходимо для вычисления и минимизации хи-квадрат, определяется как интеграл функции распределения от x_i = левый край до x_i + 1 = правый край.
Мне нужно разумное начальное предположение для моих оптимизированных параметров, так как они дадут мне разумное предположение для минимизированного значения Хи-квадрат. Я выбираю 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
вызывает chisquare
из модуля scipy для возврата результата.
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]
Я не знаю как, но я хотел бы наложить ограничения на свою систему. В частности, максимальное значение списка высот разделенных данных должно быть больше нуля (как и Хи-квадрат из-за экспоненциального члена, который остается после дифференцирования).
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 с использованием значения предположения. Чи-квадрат и значение предположения вызывают друг друга функции и т. Д. Как я могу правильно передать свои аргументы?
args = (mu, sigma, normc])
.args
обычно представляет собой кортеж, а не список. Это делаетargs1 = (x,)+args
,your_function(*args1)
. - person hpaulj   schedule 03.03.2017args
содержит текущие константы; оптимизация по 1-му аргументу.args
значения могут быть изменены в некотором внешнем цикле. - person hpaulj   schedule 03.03.2017