Как распознать функцию
Есть две функции - каким способом можно определить тип функции или смещение на какой то бок? Тоесть чтобы можно было сказать, если есть значение равное столько то, то это функция примерно вида такого...
from matplotlib import pyplot as plt
import numpy as np
x1 = np.linspace(0, 12, 100)
y1 = np.sin(x)*np.exp(-x/4)
x2 = np.arange(0,3*np.pi,0.1)
y2 = np.sin(x)
Ответы (1 шт):
Для подбора функции под известный набор значений можно использовать функцию scipy.optimize.curve_fit. В качестве аргументов она принимает функцию вида fn(x, p1, p2, ..., pn) и ищет такой набор значений параметров p1,...,pn, чтобы fn оказалась ближе всего к заданному набору. Помимо набора параметров curve_fit возвращает ковариационную матрицу, которая даёт возможность оценить ошибку аппроксимации.
К сожалению, curve_fit не умеет угадывать вид функции, которую использовать для аппроксимации. Это работа пользователя. curve_fit будет искать параметры даже в том случае, когда предложенная функция совсем не похожа на заданную.
Пример.
Попробуем аппроксимировать первый график простым синусом.
import scipy.optimize as spo
import numpy as np
import matplotlib.pyplot as plt
x1 = np.linspace(0, 12, 100)
y1 = np.sin(x1)*np.exp(-x1/4)
# Подбор функции как A*sin(a(x-dx))
def guess_sin(x, A, a, dx):
return A*np.sin(a*(x-dx))
params, covariancve = spo.curve_fit(guess_sin, x1, y1)
err = np.sqrt(np.diag(covariancve))
print(params, err)
Получится вот что:
(array([ 0.30108858, 0.98160253, -0.17234397]),
array([0.02448288, 0.02523105, 0.17641344]))
В первой строке идёт вектор параметров, во второй - вектор ошибок. По третьему параметру видно, что аппроксимация так себе - величина ошибки больше самого значения. Построим график полученной аппроксимации:
y1_sin = guess_sin(x1, *params)
plt.plot(x1,y1)
plt.plot(x1, y1_sin, ls='--')
Видно, что приближение несколько не удалось.
Теперь попробуем аппроксимировать другой функцией:
# Подбор функции как A*sin(a(x-d1))*(b/x)
def guess_sin_invx(x, A, a, d1, b):
return A*np.sin(a*(x-d1))*(b/x)
# Игнорируем первые две точки, так как будет деление на 0
params, covariancve = spo.curve_fit(guess_sin_invx, x1[2:], y1[2:])
err = np.sqrt(np.diag(covariancve))
print(params, err)
y1_sinexp2 = guess_sin_invx(x1[2:], *params)
plt.plot(x1,y1)
plt.plot(x1[2:], y1_sinexp2, ls='--')
Результат получится такой:
(array([1.21971316, 1.03866358, 0.23717369, 0.84078164]),
array([inf, inf, inf, inf]))
Матрица ошибок вообще не получилась из-за слишком больших чисел вблизи нуля. Поэтому качество аппроксимации можно оценивать только на глаз.
Как выглядит вектор ошибок, когда аппроксимация идеальна:
def guess_sinexp(x, A, a, d1, b):
return A*np.sin(a*(x-d1))*np.exp(-b*x)
params, covariancve = spo.curve_fit(guess_sinexp, x1, y1)
err = np.sqrt(np.diag(covariancve))
print(params, err)
Вывод (array([1.00000000e+00, 1.00000000e+00, 1.95903459e-09, 2.50000000e-01]), array([3.87359349e-10, 8.04285095e-11, 2.16429930e-10, 1.29385134e-10]))
Видите, какие крохотные ошибки? То, что ошибки порядка 1е-10 означает, что вид функции угадан точно.


