使用平均绝对偏差定制回归

时间:2020-02-25 01:45:05

标签: python numpy scipy regression scipy-optimize

this post之后,我现在非常怀疑R-squaredF-test是否能很好地表明随机噪声对某些数据的线性拟合良好。因此,我想开发一个定制的回归函数,以便既可以了解它的工作原理,又可以改进现有工具。

考虑这些随机生成的ndarray xy

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)
给定XY形状相同的ndarray的

找到使a最小的baad(X, Y, a, b)。重要的是,结果必须是绝对最小值,而不仅仅是局部值。

当然,按照SO最佳实践的精神,我已经尝试过scipy.optimize函数fminbrute的功能,如您在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])

但是,我得到的结果并不令人满意!求解器不成功,我收到消息:

由于精度损失而不一定实现所需的误差

1 个答案:

答案 0 :(得分:0)

首先,感谢this post,我意识到这不是上面的评论中讨论的普通最小二乘(OLS)回归。实际上,它由许多名称来调用,其中包括Deming回归,正交距离回归(ODR)和总最小二乘(TLS)。还有of coursea 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中找到。