Предложение от HappyDog отлично подходит для быстрого подбора, однако я хотел бы представить другой метод, который не требует каких-либо манипуляций с вашими данными. Метод будет использовать метод scipy.optimize.curve_fit
, чтобы соответствовать вашим данным.
Во-первых, нам нужно понять, что нормальная линейная регрессия найдет A и B такие, что y = Ax + B обеспечивает наилучшее соответствие входным данным. В ваших требованиях указано, что подгонка должна проходить через конечную точку в вашем наборе данных. По сути, мы будем отбрасывать линию, которая проходит через вашу конечную точку, и вращать ее вокруг этой точки, пока мы не сможем минимизировать ошибки.
Посмотрите на уравнение точки-наклона для линии: y-yi = m*(x-xi)
где (xi, yi)
- любая точка на этой линии. Если мы сделаем подстановку, что эта точка (xi, yi)
является конечной точкой из вашего набора данных и решим для y
, мы получим y=m*(x-xf)+yf
. Эта модель нам подойдет.
Перевод этой модели в python -функцию, мы имеем:
def model(x, m, xf, yf):
return m*(x-xf)+yf
Мы создаем набор фиктивных данных для этого примера и просто для В демонстрационных целях мы значительно сместим окончательное значение y:
x = np.linspace(0, 10, 100)
y = x + np.random.uniform(0, 3, len(x))
y[-1] += 10
Мы почти готовы выполнить подгонку. Функция curve_fit
ожидает вызова вызываемой функции (model
), данных x и y и списка догадок каждого параметра, который мы пытаемся подогнать. Поскольку наш model
принимает два дополнительных «постоянных» аргумента (xf
и yf
), мы используем functools.partial
для «установки» этих аргументов на основе наших данных.
partial_model = functools.partial(model, xf=x[-1], yf=y[-1])
p0 = [y[-1]/x[-1]] # Initial guess for m, as long as xf != 0
Теперь мы можем fit!
best_fit, covar = curve_fit(partial_model, x, y, p0=p0)
print("Best fit:", best_fit)
y_fit = model(x, best_fit[0], x[-1], y[-1])
intercept = model(0, best_fit[0], x[-1], y[-1]) # The y-intercept
И мы посмотрим на результаты:
plt.plot(x, y, "g*") # Input data will be green stars
plt.plot(x, y_fit, "r-") # Fit will be a red line
plt.legend(["Sample Data", f"y=mx+b ; m={best_fit[0]:.4f}, b={intercept:.4f}"])
plt.show()
Объединение всего этого в один блок кода и включая импорт дает:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
import functools
def model(x, m, xf, yf):
return m*(x-xf)+yf
x = np.linspace(0, 10, 100)
y = x + np.random.uniform(0, 3, len(x))
y[-1] += 10
partial_model = functools.partial(model, xf=x[-1], yf=y[-1])
p0 = [y[-1]/x[-1]] # Initial guess for m, as long as xf != 0
best_fit, covar = curve_fit(partial_model, x, y, p0=p0)
print("Best fit:", best_fit)
y_fit = model(x, best_fit[0], x[-1], y[-1])
intercept = model(0, best_fit[0], x[-1], y[-1]) # The y-intercept
plt.plot(x, y, "g*") # Input data will be green stars
plt.plot(x, y_fit, "r-") # Fit will be a red line
plt.legend(["Sample Data", f"y=mx+b ; m={best_fit[0]:.4f}, b={intercept:.4f}"])
plt.show()
Мы видим линию, проходящую через конечную точку, как требуется, и нашли наилучший уклон для представления этого набора данных.