如何在线性回归中强制零拦截?

Kyr*_*far 18 python numpy scipy linear-regression

如果这个问题已经得到解答,我有点道歉,我已经看了一眼,找不到我想要的具体内容.

我有一些或多或少的线性数据形式

x = [0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 20.0, 40.0, 60.0, 80.0]
y = [0.50505332505407008, 1.1207373784533172, 2.1981844719020001, 3.1746209003398689, 4.2905482471260044, 6.2816226678076958, 11.073788414382639, 23.248479770546009, 32.120462301367183, 44.036117671229206, 54.009003143831116, 102.7077685684846, 185.72880217806673, 256.12183145545811, 301.97120103079675]
Run Code Online (Sandbox Code Playgroud)

scipy.optimize.leastsq用来拟合线性回归:

def lin_fit(x, y):
    '''Fits a linear fit of the form mx+b to the data'''
    fitfunc = lambda params, x: params[0] * x + params[1]    #create fitting function of form mx+b
    errfunc = lambda p, x, y: fitfunc(p, x) - y              #create error function for least squares fit

    init_a = 0.5                            #find initial value for a (gradient)
    init_b = min(y)                         #find initial value for b (y axis intersection)
    init_p = numpy.array((init_a, init_b))  #bundle initial values in initial parameters

    #calculate best fitting parameters (i.e. m and b) using the error function
    p1, success = scipy.optimize.leastsq(errfunc, init_p.copy(), args = (x, y))
    f = fitfunc(p1, x)          #create a fit with those parameters
    return p1, f    
Run Code Online (Sandbox Code Playgroud)

它工作得很漂亮(虽然我不确定scipy.optimize是否适合在这里使用,它可能有点超过顶部?).

但是,由于数据点所处的方式,它不会在0处给我一个y轴拦截.我知道在这种情况下它必须为零,if x = 0 than y = 0.

有什么方法可以强制这个吗?

Joe*_*ton 33

正如@AbhranilDas所提到的,只需使用线性方法.不需要像这样的非线性求解器scipy.optimize.lstsq.

通常,您可以使用numpy.polyfit一条线来匹配数据,但在这种情况下,您需要numpy.linalg.lstsq直接使用,因为您希望将截距设置为零.

作为一个简单的例子:

import numpy as np
import matplotlib.pyplot as plt

x = np.array([0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 
              20.0, 40.0, 60.0, 80.0])

y = np.array([0.50505332505407008, 1.1207373784533172, 2.1981844719020001,
              3.1746209003398689, 4.2905482471260044, 6.2816226678076958,
              11.073788414382639, 23.248479770546009, 32.120462301367183, 
              44.036117671229206, 54.009003143831116, 102.7077685684846, 
              185.72880217806673, 256.12183145545811, 301.97120103079675])

# Our model is y = a * x, so things are quite simple, in this case...
# x needs to be a column vector instead of a 1D vector for this, however.
x = x[:,np.newaxis]
a, _, _, _ = np.linalg.lstsq(x, y)

plt.plot(x, y, 'bo')
plt.plot(x, a*x, 'r-')
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 谢谢。这就是我一直在寻找的答案。我找到了另一个示例,该示例说明如何使用带有拦截器的linalg.lstsq,这对我的整体理解有所帮助。为此,将x = x [:,np.newaxis]替换为x = np.vstack([x,np.ones(len(x))])。T` (2认同)

Abh*_*Das 9

我不擅长这些模块,但我有一些统计经验,所以这就是我所看到的.你需要改变你的拟合函数

fitfunc = lambda params, x: params[0] * x + params[1]  
Run Code Online (Sandbox Code Playgroud)

至:

fitfunc = lambda params, x: params[0] * x 
Run Code Online (Sandbox Code Playgroud)

同时删除该行:

init_b = min(y) 
Run Code Online (Sandbox Code Playgroud)

并将下一行更改为:

init_p = numpy.array((init_a))
Run Code Online (Sandbox Code Playgroud)

这应该摆脱产生y轴截距的第二个参数,并通过原点传递拟合线.在其余代码中,您可能需要进行一些小的更改.

但是,是的,我不确定这个模块是否会起作用,如果你只是像这样拔掉第二个参数.这取决于模块的内部工作原理是否可以接受此修改.例如,我不知道params参数列表在哪里被初始化,所以我不知道这样做是否会改变它的长度.

顺便说一句,既然你提到过,我实际上认为这只是一种优化斜坡的过度方法.您可以稍微阅读线性回归并编写小代码,以便在一些背后的包络演算之后自己完成.这真的非常简单明了.事实上,我只做了一些计算,我猜优化的斜率就是<xy>/<x^2>,即x*y乘积的平均值除以x ^ 2的平均值.

  • 事实上,正如 Abhranil 在结尾处所写的那样,“y = a*x”的最小二乘拟合的正确解决方案就是“a=x.dot(y)/x.dot(x)”。 (2认同)

Xav*_*hot 7

从 开始,我们可以直接使用标准库执行截距强制为 0 的Python 3.11操作:linear_regression

from statistics import linear_regression

# x = [0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 20.0, 40.0, 60.0, 80.0]
# y = [0.50505332505407008, 1.1207373784533172, 2.1981844719020001, 3.1746209003398689, 4.2905482471260044, 6.2816226678076958, 11.073788414382639, 23.248479770546009, 32.120462301367183, 44.036117671229206, 54.009003143831116, 102.7077685684846, 185.72880217806673, 256.12183145545811, 301.97120103079675]
slope, intercept = linear_regression(x, y, proportional=True)
# (4.1090219715758085, 0.0)
Run Code Online (Sandbox Code Playgroud)

该参数proportional设置为True,以指定xy被假定为成正比(并且数据适合穿过原点的线)。