Кривая, соответствующая последним точкам данных - PullRequest
0 голосов
/ 12 июня 2018

Я пытаюсь подогнать кривую к набору точек данных, но хотел бы сохранить определенные характеристики.

Как и на этом графике, у меня есть кривые, которые почти оказываются линейными, а некоторые из них - нет.Мне нужна функциональная форма для интерполяции между данными точками данных или после последней заданной точки.

Кривые были созданы с использованием простой регрессии

def func(x, d, b, c):
    return c + b * np.sqrt(x) + d * x

enter image description here

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

Я бы хотел сохранить порядок как можно более низким, возможно, 3 евро будет в порядке.

Данные, использованные для создания кривой с отрицательным наклоном, равны

x_data = [     100,      560,      791,     1117,     1576,     2225,
       3141,     4434,     6258,     8834,    12470,    17603,
      24848,    35075,    49511,    69889,    98654,   139258,
     196573,   277479,   391684,   552893,   780453,  1101672,
    1555099,  2195148,  3098628,  4373963,  6174201,  8715381,
   12302462, 17365915]
y_data = [  7,   8,   9,  10,  11,  12,  14,  16,  21,  27,  32,  30,  31,
    38,  49,  65,  86, 108, 130, 156, 183, 211, 240, 272, 307, 346,
   389, 436, 490, 549, 473, 536]

А для положительного

x_data = [     100,      653,      950,     1383,     2013,     2930,
       4265,     6207,     9034,    13148,    19136,    27851,
      40535,    58996,    85865,   124969,   181884,   264718,
     385277,   560741,   816117,  1187796,  1728748,  2516062,
    3661939,  5329675,  7756940, 11289641, 16431220, 23914400,
   34805603, 50656927]
y_data = [  6,   6,   7,   7,   8,   8,   9,  10,  11,  12,  14,  16,  18,
    21,  25,  29,  35,  42,  50,  60,  72,  87, 105, 128, 156, 190,
   232, 284, 347, 426, 522, 640]

Подгонка кривой выполняется простым использованием

popt, pcov = curve_fit(func, x_data, y_data)

Для сюжета

plt.plot(xdata, func(xdata, *popt), 'g--', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt))
plt.plot(x_data, y_data, 'ro')
plt.xlabel('Volume')
plt.ylabel('Costs')
plt.show()

1 Ответ

0 голосов
/ 14 июня 2018

Простое решение может выглядеть так:

import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import least_squares

def fit_function(x, a, b, c, d):
    return a**2 + b**2 * x + c**2 * abs(x)**d 

def residuals( params, xData, yData):
    diff = [ fit_function(x, *params ) - y for x, y in zip( xData, yData ) ]
    return diff

fit1 = least_squares( residuals, [ .1, .1, .1, .5 ], loss='soft_l1', args=( x1Data, y1Data ) )
print fit1.x
fit2 = least_squares( residuals, [ .1, .1, .1, .5 ], loss='soft_l1', args=( x2Data, y2Data ) )
print fit2.x

testX1 = np.linspace(0, 1.1 * max( x1Data ), 100 )
testX2 = np.linspace(0, 1.1 * max( x2Data ), 100 )
testY1 = [ fit_function( x, *( fit1.x ) ) for x in testX1 ]
testY2 = [ fit_function( x, *( fit2.x ) ) for x in testX2 ]

fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.scatter( x1Data, y1Data )
ax.scatter( x2Data, y2Data )
ax.plot( testX1, testY1 )
ax.plot( testX2, testY2 )
plt.show()

, обеспечивающее

>>[ 1.00232004e-01 -1.10838455e-04  2.50434266e-01  5.73214256e-01]
>>[ 1.00104293e-01 -2.57749592e-05  1.83726191e-01  5.55926678e-01]

и

soft fit

Он принимает параметры в виде квадратов, поэтому обеспечивает положительный наклон.Естественно, подгонка ухудшается, если следование по убывающим точкам в конце набора данных 1 запрещено.По этому поводу я бы сказал, что это просто статистические выбросы.Поэтому я использовал least_squares, который может справиться с этим с мягкой потерей.См. этот документ для деталей.В зависимости от того, каков реальный набор данных, я бы подумал об их удалении.Наконец, я ожидаю, что нулевой объем приводит к нулевым затратам, поэтому постоянный член в функции подгонки, похоже, не имеет смысла.

Так что, если функция имеет тип a**2 * x + b**2 * sqrt(x), она выглядит следующим образом:

simplified

, где зеленый график - результат leastsq, т.е. без опции f_scale least_squares.

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