Как расставить приоритеты для некоторых точек над другими, используя кривую от SciPy - PullRequest
0 голосов
/ 27 марта 2020

Я хочу смоделировать следующую кривую:

enter image description here

Чтобы выполнить это, я использую Curve_fit от SciPy, подгоняя экспоненциальную функцию.

def exponenial_func(x, a, b, c):
    return a * b**(c*x)

popt, pcov = curve_fit(exponenial_func, x, y, p0=(1,2,2), 
                       bounds=((0, 0, 0), (np.inf, np.inf, np.inf)))

Когда я впервые это делаю, я получаю это:

enter image description here

Что минимизирует остатки, каждая точка с тот же уровень важности. Я хочу получить кривую, которая придает большее значение последним значениям кривой (например, от оси x 30), чем первым значениям, поэтому она лучше подходит к концу кривой, чем к началу этого

Я знаю, что отсюда есть много способов приблизиться к этому (прежде всего, определите, какое значение я хочу придать каждому из остатков). Мой вопрос здесь заключается в том, чтобы получить представление о том, как к этому приблизиться.

Одна идея, которая у меня возникла, - это изменить значение сигмы, чтобы взвесить каждую точку данных ее обратным значением.

popt, pcov = curve_fit(exponenial_func, x, y, p0=(1,2,2), 
                       bounds=((0, 0, 0), (np.inf, np.inf, np.inf)),
                       sigma=1/y)

В этом случае я получаю что-то похожее на то, что искал:

enter image description here

Это не выглядит плохо, но я ищу другой способ сделать это, чтобы я мог «контролировать» каждую из точек данных, например, взвешивать все остатки линейным способом или экспоненциально, или даже выбирать его вручную (а не все их обратное, как в предыдущем случае).

Заранее спасибо

1 Ответ

1 голос
/ 28 марта 2020

Прежде всего, обратите внимание, что нет необходимости в трех коэффициентах. Поскольку

a * b**(c*x) = a * exp(log(b)*c*x).

, мы можем определить k = log(b)*c.

Вот совет, как вы могли бы решить вашу проблему руками с scipy.optimize.least_squares и вектором приоритета:

import numpy as np
from scipy.optimize import least_squares

def exponenial_func2(x, a, k):
    return a * np.exp(k*x)

# returns the vector of residuals
def fitwrapper2(coeffs, *args):
    xdata, ydata, prio = args
    return prio*(exponenial_func2(xdata, *coeffs)-ydata)

# Data
n = 31
xdata = np.arange(n)
ydata = np.array([155.0,229,322,453,655,888,1128,1694,
                  2036,2502,3089,3858,4636,5883,7375,
                  9172,10149,12462,12462,17660,21157,
                  24747,27980,31506,35713,41035,47021,
                  53578,59138,63927,69176])

# The priority vector
prio = np.ones(n)
prio[-1] = 5

res = least_squares(fitwrapper2, x0=[1.0,2.0], bounds=(0,np.inf), args=(xdata,ydata,prio))
  • С prio[-1] = 5 мы даем последней точке высокий приоритет.

  • res.x содержит ваши оптимальные коэффициенты. Здесь a, k = res.x.

  • Обратите внимание, что для prio = np.ones(n) это обычная аппроксимация методом наименьших квадратов (как это делает Curve_fit), где все точки имеют одинаковый приоритет .

Вы можете контролировать приоритет каждой точки, увеличивая ее значение в массиве prio. Сравнение обоих результатов дает мне:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...