【问题标题】:linear regression with a forced non-zero y-intercept具有强制非零 y 截距的线性回归
【发布时间】:2020-12-03 21:03:54
【问题描述】:

我想在 y 截距强制为 0.115 的情况下运行线性回归。这是我尝试过的代码。我设置为 fit_intercept=True 以获得非零 y 截距,但我可以将其设置为一个值吗?

另外,我怎样才能绘制出最适合的线而不是连接每个点的线?

提前致谢。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
x=np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).reshape(-1,1)
y=np.array([0.113, 0.116, 0.130, 0.150, 0.150, 0.160, 0.180, 0.210, 0.220, 0.260, 0.280])
regression=LinearRegression(fit_intercept=True).fit(x,y)
r_sq=round(regression.score(x,y),4)
m=round(regression.coef_[0],4)
b=round(regression.intercept_,4)
print("r_sq:", r_sq,"m:",m,"b:",b)
plt.figure()
plt.scatter(x,y)
plt.title('A')
plt.ylabel('X')
plt.xlabel('Y')
plt.plot(x,y,'r--',label='measured')
plt.legend(loc='best')

【问题讨论】:

    标签: python linear-regression


    【解决方案1】:

    从数据中减去要修正的 y 截距并设置 fit_intercept=False

    例如

    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.linear_model import LinearRegression
    
    x = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).reshape(-1, 1)
    y = np.array([0.113, 0.116, 0.130, 0.150, 0.150, 0.160, 0.180, 0.210, 0.220, 0.260, 0.280])
    
    fig, ax = plt.subplots()
    
    for fit, y_intercept in zip((True, False), (0.0, 0.115)):
        regression = LinearRegression(fit_intercept=fit)
        regression.fit(x, y - y_intercept)
    
        r_sq = regression.score(x, y - y_intercept)
        m = regression.coef_[0]
        b = regression.intercept_ + y_intercept
    
        print(f"Fit intercept: {regression.fit_intercept}")
        print(f"r_sq: {r_sq:0.4f}\nm: {m:0.4f}\nb: {b:0.4f}")
    
        ax.plot(x, y, "bo")
        ax.plot(
            x,
            regression.predict(x) + y_intercept,
            "r" + "--" * fit,
            label=f"Fit Intercept: {regression.fit_intercept}",
        )
    
    ax.set_title("A")
    ax.set_ylabel("X")
    ax.set_xlabel("Y")
    
    ax.legend(loc="best")
    
    plt.show()
    

    哪些打印:

    Fit intercept: True
    r_sq: 0.9473
    m: 0.0017
    b: -0.0192
    Fit intercept: False
    r_sq: 0.9112
    m: 0.0014
    b: 0.0000
    

    【讨论】:

    • 结果与我从 Excel 中得到的不符。我得到:r_sq:-3.1784 m:0.0014 b:0.0
    • 但是,在 Excel 中,结果为 r-squared=0.9473,斜率为 0.0014(匹配),y 截距为 0.115 强制。我改为“r_sq=round(regression.score(x,y-y_intercept),4)”,但 r-squared 仍然不匹配。我得到 0.9112 而不是 0.9473。我需要更改任何其他参数吗?
    • 我已经更新了我的答案,看看。当您拟合截距时,您将获得与 excel 相同的 R^2 值。我不知道 Excel 在幕后做了什么,但我玩了一下:您可以将截距设置为 any 非零值,它会返回 same R^2 值。在我看来,这就像 Excel 中的一个错误。
    • 它有效,而且似乎 Excel 为两者提供了相同的 R^2 值,因此可能是一个错误。我得到的数据有点不同,但它来自您的代码的复制和粘贴,它与 Excel 中的结果匹配,除了“拟合截距:假”案例的 R^2 值。拟合截距:真 r_sq:0.9473 m:0.0017 b:0.0958 拟合截距:假 r_sq:0.9112 m:0.0014 b:0.1150
    【解决方案2】:

    fit_intercept 上的帖子 https://stackoverflow.com/questions/46779605
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    from sklearn.metrics import r2_score
    from sklearn.linear_model import LinearRegression
    
    x=np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).reshape(-1,1)
    y=np.array([0.113, 0.116, 0.130, 0.150, 0.150, 0.160, 0.180, 0.210, 0.220, 0.260, 0.280])
    
    lr_fi_true = LinearRegression(fit_intercept=True)
    lr_fi_false = LinearRegression(fit_intercept=False)
    
    lr_fi_true.fit(x, y)
    lr_fi_false.fit(x, y)
    
    print('Intercept when fit_intercept=True : {:.5f}'.format(lr_fi_true.intercept_))
    print('Intercept when fit_intercept=False : {:.5f}'.format(lr_fi_false.intercept_))
    
    lr_fi_true_yhat = np.dot(x, lr_fi_true.coef_) + lr_fi_true.intercept_
    lr_fi_false_yhat = np.dot(x, lr_fi_false.coef_) + lr_fi_false.intercept_
    
    plt.scatter(x, y, label='Actual points')
    plt.plot(x, lr_fi_true_yhat, 'r--', label='fit_intercept=True')
    plt.plot(x, lr_fi_false_yhat, 'r-', label='fit_intercept=False')
    plt.legend()
    
    plt.vlines(0, 0, y.max())
    plt.hlines(0, x.min(), x.max())
    
    plt.show()
    

    印刷:
    Intercept when fit_intercept=True : 0.09577
    Intercept when fit_intercept=False : 0.00000
    


    【讨论】:

    • 这个答案修复了情节,上面的答案提供了如何强制非零 y 截距。
    【解决方案3】:

    我找到了一个通用解决方案,它给出了相同的答案,但也允许我通过简单地修改函数来拟合非线性方程。

    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    import numpy as np
    
    #set y-intercept
    b=0.115
    
    #Fitting function
    def func(x, m):
        return (x*m)+b
    
    #Experimental x and y data points    
    x_A1 = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
    y_A1 = np.array([0.113, 0.116, 0.130, 0.150, 0.150, 0.160, 0.180, 0.210, 0.220, 0.260, 0.280])
    
    #Plot experimental data points
    plt.plot(x_A1, y_A1, 'bo', label='experimental')
    
    #Perform the curve-fit
    popt, pcov = curve_fit(func, x_A1, y_A1) #, initialGuess)
    #print(popt)
    
    #x values for the fitted function
    x_A1_Fit = np.arange(x_A1[0], x_A1[-1], 0.1)
    
    residuals = y_A1- func(x_A1, *popt)
    ss_res = np.sum(residuals**2)
    ss_tot = np.sum((y_A1-np.mean(y_A1))**2)
    r_sq = 1 - (ss_res / ss_tot)
    
    #Plot the fitted function
    plt.plot(x_A1_Fit, func(x_A1_Fit, *popt), 'r--', label='fitted: m=%5.4f' % tuple(popt))
    
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()
    plt.show()
    print ('r_sq=', "%.4f"%r_sq, 'm=', "%.4f"%popt, "b=", "%.4f"%b)
    

    【讨论】:

      猜你喜欢
      • 2018-06-11
      • 2015-05-30
      • 2019-02-23
      • 2019-05-27
      • 2016-03-04
      • 2022-01-09
      • 2011-11-12
      • 1970-01-01
      • 2018-02-21
      相关资源
      最近更新 更多