Прежде всего, благодаря этому посту Я понял, что это не обычная регрессия наименьших квадратов (OLS), как обсуждалось в комментариях выше. На самом деле его называют многими именами, среди которых регрессия Деминга, регрессия ортогонального расстояния (ODR) и наименьшие квадраты (TLS). Также есть, конечно , Python пакет scipy.odr
для этого! Его синтаксис немного странный, и документация не очень помогает, но хороший учебник можно найти здесь .
Nex Я обнаружил небольшую ошибку в определении aad
, переименовал и исправил ее на:
def aaod(a, b, X, Y): # assumes X and Y are of the identical shape/size
n = X.size # still highly unsafe! don't use it in real production
U = (a * X + Y - b) / 2 / a
V = (a * X + Y + b) / 2
E = np.sqrt(np.power((X - U), 2) + np.power((Y - V), 2))
return E.sum() / n
, обозначая среднее абсолютное ортогональное расстояние. Теперь определяем нашу функцию подбора как:
from scipy.optimize import minimize
from scipy.stats import linregress
def odrFit(X, Y):
X0 = linregress(X, Y) # wait this is cheating!
aaod_ = lambda P: aaod(P[0], P[1], X, Y)
res = minimize(aaod_, x0=X0[:2], method = 'Nelder-Mead')
res_list = res.x.tolist()
res_list.append(aaod_(res_list))
return res_list
, что не обязательно является наиболее эффективной и канонической реализацией. Обходной путь с временной функцией lambda
, которую я узнал из здесь и method = 'Nelder-Mead'
из здесь . Реализацию scipy.odr
можно также выполнить следующим образом:
from scipy.odr import Model, ODR, RealData
def f(B, x):
return B[0]*x + B[1]
linear = Model(f)
mydata = RealData(x, y)
myodr = ODR(mydata, linear, beta0=[1., 2.])
myoutput = myodr.run()
Теперь сравниваем результат между нашей заказной функцией odrFit()
и scipy.stats.linregress()
:
slope, intercept, r_value, p_value, std_err = linregress(x,y)
print(*odrFit(x, y))
# --> 1.4804181575739097, 0.47304584702448255, 0.6008218016339527
print(slope, intercept, aaod(slope, intercept, x, y))
# --> 1.434483032725671 0.5747705643012724 0.608021569291401
print(*myoutput.beta, aaod(*myoutput.beta, x, y))
# --> 1.5118079563432785 0.23562547897245803 0.6055838996104704
, которая показывает наш Функция на самом деле более точная, чем метод регрессии Скипи с наименьшим абсолютным отклонением. На самом деле это может быть просто удача, и нужно сделать больше тестов, чтобы сделать надежный вывод. Полный код можно найти здесь .