Есть несколько вариантов, я перечислю несколько ниже.Последний, кажется, дает лучший результат.Следует ли вам использовать сплайн или реальную функцию, зависит от того, что вы хотите сделать с выводом;Ниже я перечисляю две аналитические функции, которые можно использовать, но я не знаю, в каком контексте были получены данные, поэтому трудно найти лучшую для вас.
Вы можете играть с s
, напримердля s=0.005
график выглядит следующим образом (все еще не очень красивым, но вы можете изменить его):
Но я бы действительно использовал "правильной "функции и подгонки, используя, например, curve_fit
Приведенная ниже функция все еще не идеальна, так как она монотонно увеличивается, поэтому в конце мы пропускаем уменьшение;график выглядит следующим образом:
Это полный код как для сплайна, так и для фактического соответствия:
from scipy.interpolate import UnivariateSpline
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
def func(x, ymax, n, k, c):
return ymax * x ** n / (k ** n + x ** n) + c
x=np.array([ 1.00094909, 1.08787635, 1.17481363, 1.2617564, 1.34867881, 1.43562284,
1.52259341, 1.609522, 1.69631283, 1.78276102, 1.86426648, 1.92896789,
1.9464453, 1.94941586, 2.00062852, 2.073691, 2.14982808, 2.22808316,
2.30634034, 2.38456905, 2.46280126, 2.54106611, 2.6193345, 2.69748825])
y=np.array([-0.10057627, -0.10172142, -0.10320428, -0.10378959, -0.10348456, -0.10312503,
-0.10276956, -0.10170055, -0.09778279, -0.08608644, -0.05797392, 0.00063599,
0.08732999, 0.16429878, 0.2223306, 0.25368884, 0.26830932, 0.27313931,
0.27308756, 0.27048902, 0.26626313, 0.26139534, 0.25634544, 0.2509893 ])
popt, pcov = curve_fit(func, x, y, p0=[y.max(), 2, 2, -0.1], bounds=([0, 0, 0, -0.2], [0.4, 45, 2000, 10]))
xfit = np.linspace(x.min(), x.max(), 200)
plt.scatter(x, y)
plt.plot(xfit, func(xfit, *popt))
plt.show()
s = UnivariateSpline(x, y, k=3, s=0.005)
xfit = np.linspace(x.min(), x.max(), 200)
plt.scatter(x, y)
plt.plot(xfit, s(xfit))
plt.show()
Третий вариант - использовать более продвинутую функцию, которая также может воспроизвести уменьшение в конце и differential_evolution
для подгонки;что, кажется, лучше всего подходит:
Код выглядит следующим образом (используя те же данные, что и выше):
from scipy.optimize import curve_fit, differential_evolution
def sigmoid_with_decay(x, a, b, c, d, e, f):
return a * (1. / (1. + np.exp(-b * (x - c)))) * (1. / (1. + np.exp(d * (x - e)))) + f
def error_sigmoid_with_decay(parameters, x_data, y_data):
return np.sum((y_data - sigmoid_with_decay(x_data, *parameters)) ** 2)
res = differential_evolution(error_sigmoid_with_decay,
bounds=[(0, 10), (0, 25), (0, 10), (0, 10), (0, 10), (-1, 0.1)],
args=(x, y),
seed=42)
xfit = np.linspace(x.min(), x.max(), 200)
plt.scatter(x, y)
plt.plot(xfit, sigmoid_with_decay(xfit, *res.x))
plt.show()
Подгонка довольно чувствительна к границам, поэтому будьте осторожны, когда вы играете с этим ...