
(
Код: Выделить всё
xs[img]https://i.sstatic .net/rUMpuq0k.png[/img]
где v и L фиксированы для заданных параметров. Вычислить fp можно относительно быстро, векторизовав его и воспользовавшись некоторой универсальной фильтрацией. Следующий код реализует эту задачу оптимизации, где функция cfit (через fitf) медленно корректирует значения xs, вычисляя fp на каждом шаге и сравнивая его с реальным значением. data

(
Код: Выделить всё
list
Вопрос: Есть ли способ улучшить этот метод подгонки для этой конкретной функции и способ ее вычисления? Я пробовал поиграться с scipy.optimize, но все кажется медленнее, чем этот простой метод мультипликативного градиента.
Вот реализация кода, в которой отслеживается среднеквадратическая ошибка< /p>
Код: Выделить всё
import numpy as np
import math
def fitfunction(list, maxiter, error_threshold):
v = 1.4
st = 5
exp_v = np.exp(-1/v)
x00 = np.array([(math.pi/(4*v))*i**(-2) for i in list])
lm = 1000
def mse(y_true, y_pred):
mse_value = sum((yt - yp) ** 2 for yt, yp in zip(y_true, y_pred)) / len(y_true)
return mse_value
def fast_roll_add(dst, src, shift):
dst[shift:] += src[:-shift]
dst[:shift] += src[-shift:]
# Main function
def fp(x, L, v):
n = len(x)
y = np.zeros(n)
last_exp_2_raw = np.zeros(n)
last_exp_2 = np.ones(n)
unitary = x.copy()
for k in range(L+1):
if k != 0:
fast_roll_add(unitary, x, k)
fast_roll_add(unitary, x, -k)
exp_1_raw = last_exp_2_raw
exp_1 = last_exp_2
exp_2_raw = exp_1_raw + unitary / v
exp_2 = np.exp(-exp_2_raw)
y += (exp_1 - exp_2) / unitary
last_exp_2_raw = exp_2_raw
last_exp_2 = exp_2
return y
# Fitting functions
def fitf(time, lst, x0, j):
return x0[j] * (lst[j] / time[j])**2
def cfit(time, lst, x0):
result = np.empty_like(x0)
for j in range(len(x0)):
if fitf(time, lst, x0, j) < 10**(-20):
result[j] = 10**(-20)
elif abs(time[j] - lst[j]) < .5:
result[j] = x0[j]
else:
result[j] = fitf(time, lst, x0, j)
return result
xs = x00
ys = fp(xs, len(xs)//st, v)
err = 10**10
for j in range(maxiter):
if err > error_threshold:
xs = cfit(list, ys, xs) # Fitting
ys = fp(xs, len(xs)//st, v) # Update function values
err = mse(list[lm:-lm], ys[lm:-lm])
print(str(j+1) + '/' + str(maxiter) + ' err: ' + str('{:.20f}'.format(err)), end="\r")
else:
break
fire_rates = ['{:.20f}'.format(i) for i in xs]
time_sim = ys
return [fire_rates, time_sim]
Минимальный рабочий пример:
Код: Выделить всё
from scipy.ndimage import gaussian_filter1d
# Data generation
np.random.seed(18)
data = np.random.normal(loc=0, scale=10, size=10000).cumsum()
data = (data - data.min()) / (data.max() - data.min()) * 500
# Gaussian smoothing
data = gaussian_filter1d(data, sigma=50)
data_fit = fitfunction(data, 100, 2)
Код: Выделить всё
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(data, label='Data')
plt.plot(data_fit[1], label='Data Fit')
plt.xlabel('Index')
plt.ylabel('Value')
plt.title('Data and Data Fit')
plt.legend()
plt.show()

Краткие комментарии:
- Мой мультипликативный метод кажется неоптимальным в отношении локальных максимумов, как показано на примере сюжет выше. Однако я хочу гарантировать наилучшее соответствие.
- В частности, при использовании действительно большого числа итераций алгоритм подгонки вообще не сходится. Это можно увидеть примерно на 200 шагах итерации, когда локальные значения расходятся с реальными значениями данных в районе локальных максимумов.
- Реализация fp носит периодический характер, что приводит к к массовым ошибкам в концовках. Следовательно, ошибка err рассчитывается без учета этих областей.
- Функция подгонки обеспечивает еще более быструю подгонку
Код: Выделить всё
def fitf(time, lst, x0, j):
return x0[j]**(np.log(time[j]) / np.log(lst[j]))
Подробнее здесь: https://stackoverflow.com/questions/786 ... ing-method