在this post之后,我现在非常怀疑R-squared或F-test是否能很好地表明随机噪声对某些数据的线性拟合良好。因此,我想开发一个定制的回归函数,以便既可以了解它的工作原理,又可以改进现有工具。
考虑这些随机生成的ndarray x
和y
:
import numpy as np
np.random.seed(42)
x = np.random.rand(30) * 10
y = 1.5 * x + 0.3 + (np.random.rand(30) - 0.5) * 3.5
现在我可以使用以下命令定义任何一组数据点的平均/均值绝对偏差:
def aad(X, Y, a, b): # assumes X and Y are of the identical shape/size
n = X.size # highly unsafe!
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
在我看来,这是将y = a * x + b
行适合于数据点对的最佳方式。该函数只需找到假定线与任何数据点的最接近点,然后计算该点与线之间的垂直距离即可。
现在我需要一个功能,比如说:
linearFit(X, Y)
给定X
和Y
形状相同的ndarray的找到使a
最小的b
和aad(X, Y, a, b)
。重要的是,结果必须是绝对最小值,而不仅仅是局部值。
当然,按照SO最佳实践的精神,我已经尝试过scipy.optimize
函数fmin
和brute
的功能,如您在above-mentioned post和{ {3}}。但是,似乎我无法理解这些功能的正确语法。如果您可以帮助我为假定的linearFit
函数找到规范和高性能的实现,我们将不胜感激。感谢您的提前支持。
PS 。临时解决方案提供了here:
from scipy.optimize import minimize
aad_ = lambda P: aad(P[0], P[1], x1, y1)
minimize(aad_, x0=[X0, Y0])
但是,我得到的结果并不令人满意!求解器不成功,我收到消息:
由于精度损失而不一定实现所需的误差
答案 0 :(得分:0)
首先,感谢this post,我意识到这不是上面的评论中讨论的普通最小二乘(OLS)回归。实际上,它由许多名称来调用,其中包括Deming回归,正交距离回归(ODR)和总最小二乘(TLS)。还有of course,a Python package scipy.odr
!它的语法有点怪异,文档没有太大帮助,但是可以找到here很好的教程。
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
不一定是最高性能和规范的实现。我从here中学到了lambda
临时功能,而从here学到了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
这表明我们的功能实际上比Scipy的最小绝对偏差回归方法更准确。这实际上可能仅仅是运气,需要做更多的测试才能得出可靠的结论。完整的代码可以在here中找到。