Использование scipy.optimize.minimize с дискретным ядром Гаусса

Я использую scipy.optimize.minimize, чтобы попытаться определить оптимальные параметры функции плотности вероятности (PDF). Мой PDF включает в себя дискретное ядро ​​Гаусса ( https://en.wikipedia.org/wiki/Gaussian_function и https://en.wikipedia.org/wiki/Scale_space_implementation).

Теоретически, я знаю среднее значение PDF (где PDF должен быть в центре). Так что, если бы я рассчитал ожидаемое значение моего PDF, я должен восстановить среднее значение, которое я уже знаю. В моем PDF-файле выбраны дискретные значения n (которые никогда не должны быть отрицательными и должны начинаться с 0, чтобы иметь какой-либо физический смысл), и я пытаюсь определить оптимальное значение t ("коэффициент масштабирования"), чтобы восстановить среднее значение из PDF (который опять же я знаю заранее).

Мой минимальный рабочий пример для определения оптимального "коэффициента масштабирования" t следующий:

#!/usr/bin/env python3                                                                                                                                                                                      

import numpy as np
from scipy.special import iv
from scipy.optimize import minimize

def discrete_gaussian_kernel(t, n):
    return np.exp(-t) * iv(n, t)

def expectation_value(t, average):

    # One constraint is that the starting value                                                                                                                                                             
    # of the range over which I sample the PDF                                                                                                                                                              
    # should be 0.                                                                                                                                                                                          

    # Method 1 - This seems to give good, consistent results                                                                                                                                                
    int_average = int(average)
    ceiling_average = int(np.ceil(average))
    N = range(int_average - ceiling_average + 1,
              int_average + ceiling_average + 2)

    # Method 2 - The multiplicative factor for 'end' is arbitrary.                                                                                                                                          
    #            I should in principle be able make end be as large as                                                                                                                                      
    #            I want since the PDF goes to zero for large values of n,                                                                                                                                   
    #            but this seems to impact the result and I do now know why.                                                                                                                                 
    #start = 0                                                                                                                                                                                              
    #end = 2 * int(average)                                                                                                                                                                                 
    #N = range(start, end)                                                                                                                                                                                  

    return np.sum([n * discrete_gaussian_kernel(t, n - average) for n in N])

def minimize_function(t, average):
    return average - expectation_value(t, average)

if __name__ == '__main__':

    average = 8.33342
    #average = 7.33342                                                                                                                                                                                      

    solution = minimize(fun = minimize_function,
                        x0 = 1,
                        args = average)

    print(solution)
    t = solution.x[0]
    print('          solution t =', t)
    print('       given average =', average)
    print('recalculated average =', expectation_value(t, average))

У меня две проблемы с моим минимальным рабочим примером:

1) Код работает нормально для некоторых значений, которые я выбираю для переменной "среднее". Одним из примеров этого является значение 8,33342. Однако код не работает для других значений, например, 7.33342. В этом случае я получаю

 RuntimeWarning: overflow encountered in exp

поэтому я подумал, что, возможно, scipy.optimize.minimize выбирает неверное значение для t (например, большое отрицательное число). Я уверен, что это проблема, так как я напечатал значение t в функции hopeation_value, и t становится все более отрицательным. Поэтому я хотел бы добавить границы возможных значений того, что может принимать "t" ("t" не должно быть отрицательным). Глядя на документацию scipy.optimize.minimize, есть аргумент ключевого слова bounds. Итак, я попробовал:

solution = minimize(fun = minimize_function,
                    x0 = 1,
                    args = average,
                    bounds = ((0, None)))

но я получаю ошибку:

 ValueError: length of x0 != length of bounds

Я искал эту ошибку в stackru, и есть некоторые другие потоки, но я не нашел ничего полезного. Как я могу успешно установить границу?

2) Мой другой вопрос связан с тем, что scipy.optimize.minimize чувствителен к диапазону, в котором я вычисляю значение ожидания. Для среднего значения

 average = 8.33342

и метод расчета диапазона как

# Method 1 - This seems to give good, consistent results                                                                                                                                                
int_average = int(average)
ceiling_average = int(np.ceil(average))
N = range(int_average - ceiling_average + 1,
          int_average + ceiling_average + 2)

"пересчитанное среднее" составляет 8,3329696426. Но для другого метода (который имеет очень похожий диапазон),

# Method 2 - The multiplicative factor for 'end' is arbitrary.                                                                                                                                          
#            I should in principle be able make end be as large as                                                                                                                                      
#            I want since the PDF goes to zero for large values of n,                                                                                                                                   
#            but this seems to impact the result and I do now know why.                                                                                                                                 
start = 0
end = 2 * int(average)
N = range(start, end)

"пересчитанное среднее" составляет 8,31991111857. Диапазоны в каждом случае одинаковы, поэтому я не знаю, почему происходит такое большое изменение, особенно с учетом того, что мое пересчитанное среднее должно быть как можно ближе к истинному среднему. И если бы я расширил диапазон до больших значений (что я считаю разумным, так как там PDF сводится к нулю),

start = 0
end = 4 * int(average)
N = range(start, end)

"пересчитанное среднее" составляет 9.12939372912, что еще хуже. Так есть ли последовательный метод для расчета диапазона, чтобы восстановленное среднее всегда было как можно ближе к истинному среднему? Коэффициент масштабирования может принимать любое значение, поэтому я думаю, что scipy.optimize.minimize должен быть в состоянии найти коэффициент масштабирования для точного возврата к истинному среднему значению.

0 ответов

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