You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用scipy.stats.linregress复现statsmodels.OLS的残差均方误差

用scipy.stats.linregress复现statsmodels.OLS的残差均方误差

能不能用scipy.stats.linregress复现statsmodels.OLS的残差均方误差?我已经能手动复现OLS的mse_resid方法结果,现在想对linregress做同样操作,让两者的均方误差结果完全匹配。

以下是测试用的数据集和初始代码:

from scipy import stats
import statsmodels.api as sm
import numpy as np

x = [4.36944785, 5.11198779, 5.27299956, 5.79909265, 5.26269019, 6.31896811,
     5.56452041, 6.82762923, 6.85012617, 6.84481548, 5.58724866, 6.42162227,
     6.42162227, 6.69456206, 6.72862861, 6.18620862, 6.68835471, 4.8598124, 
     6.00881319, 6.36130248, 6.49072353, 5.92958914, 6.25958146, 5.84643878,
     6.3952616, 5.65248918, 6.23832463, 6.12905021, 5.29831737, 6.56667243,
     5.0937502, 6.26909628, 6.54103, 6.53958596, 6.54103, 6.53958596, 
     6.72022016, 6.60258789, 6.70563909, 6.31173481, 6.58755001, 6.78105763]

y = [0.07982600432816954, 0.07071547302656801, 0.08305002908189892, 0.09691500731442375, 
     0.10527951322283996, 0.08553662721188253, 0.09733660673707481, 0.1549839973642277, 
     0.1772936800000746, 0.08246283701630393, 0.08674307140060505, 0.09188076686886233, 
     0.08911357473202978, 0.09129630573740526, 0.08960525194538806, 0.08171381972214242, 
     0.0916409307055752, 0.08059450458219804, 0.08339172699017788, 0.08679014230487617, 
     0.094905522499886, 0.08928735113983156, 0.08660721314000525, 0.08667870850057602, 
     0.09188469815760014, 0.08602803836358593, 0.0884816080378508, 0.08737399753878625, 
     0.08867415695668976, 0.09137142512590624, 0.0928207195650323, 0.0883305622258501, 
     0.08427867843903124, 0.09098192867485894, 0.08438044851325044, 0.08439333735802305, 
     0.09041076497326207, 0.0918760449066645, 0.09080763620015583, 0.08698756784494903, 
     0.09255954314642892, 0.08921757572875405]

mod = sm.OLS(y, sm.add_constant(x, prepend=False))
res = mod.fit()
err = np.sqrt(np.sum(res.resid**2)/(res.df_resid))
print(err)
print(res.mse_resid**0.5)
print()

res = stats.linregress(x, y)
k = res.slope
b = res.intercept
y_pred = [k * x_item + b for x_item in x]
n = len(x)
error = (sum((y[i]-y_pred[i]**2 for i in range(n)))/(n-2))**0.5
print(error)
from sklearn.metrics import mean_squared_error
rmse = mean_squared_error(y_true=y, y_pred=y_pred, squared=False)
print(rmse)

问题原因

原代码中linregress部分的残差计算存在优先级错误:y[i]-y_pred[i]**2会先计算y_pred[i]的平方,再用y[i]减去这个值,这不是我们需要的残差平方(应该是(y[i] - y_pred[i])**2)。这个错误导致计算结果和OLS的残差均方误差不匹配。

修正后的代码

只需要调整残差计算的括号位置,同时可以用numpy数组操作简化代码,提升效率:

from scipy import stats
import statsmodels.api as sm
import numpy as np

x = [4.36944785, 5.11198779, 5.27299956, 5.79909265, 5.26269019, 6.31896811,
     5.56452041, 6.82762923, 6.85012617, 6.84481548, 5.58724866, 6.42162227,
     6.42162227, 6.69456206, 6.72862861, 6.18620862, 6.68835471, 4.8598124, 
     6.00881319, 6.36130248, 6.49072353, 5.92958914, 6.25958146, 5.84643878,
     6.3952616, 5.65248918, 6.23832463, 6.12905021, 5.29831737, 6.56667243,
     5.0937502, 6.26909628, 6.54103, 6.53958596, 6.54103, 6.53958596, 
     6.72022016, 6.60258789, 6.70563909, 6.31173481, 6.58755001, 6.78105763]

y = [0.07982600432816954, 0.07071547302656801, 0.08305002908189892, 0.09691500731442375, 
     0.10527951322283996, 0.08553662721188253, 0.09733660673707481, 0.1549839973642277, 
     0.1772936800000746, 0.08246283701630393, 0.08674307140060505, 0.09188076686886233, 
     0.08911357473202978, 0.09129630573740526, 0.08960525194538806, 0.08171381972214242, 
     0.0916409307055752, 0.08059450458219804, 0.08339172699017788, 0.08679014230487617, 
     0.094905522499886, 0.08928735113983156, 0.08660721314000525, 0.08667870850057602, 
     0.09188469815760014, 0.08602803836358593, 0.0884816080378508, 0.08737399753878625, 
     0.08867415695668976, 0.09137142512590624, 0.0928207195650323, 0.0883305622258501, 
     0.08427867843903124, 0.09098192867485894, 0.08438044851325044, 0.08439333735802305, 
     0.09041076497326207, 0.0918760449066645, 0.09080763620015583, 0.08698756784494903, 
     0.09255954314642892, 0.08921757572875405]

# statsmodels OLS部分
mod = sm.OLS(y, sm.add_constant(x, prepend=False))
res = mod.fit()
err = np.sqrt(np.sum(res.resid**2)/(res.df_resid))
print("OLS手动计算RMSE:", err)
print("OLS mse_resid开方:", res.mse_resid**0.5)
print()

# scipy linregress修正部分
res = stats.linregress(x, y)
k = res.slope
b = res.intercept
# 转成numpy数组更方便计算
x_arr = np.array(x)
y_arr = np.array(y)
y_pred_arr = k * x_arr + b
# 计算残差平方和,除以自由度n-2后开方
residuals = y_arr - y_pred_arr
mse_resid = np.sum(residuals**2) / (len(x_arr) - 2)
rmse_linregress = np.sqrt(mse_resid)
print("linregress修正后RMSE:", rmse_linregress)

结果说明

修正后,linregress计算出的残差均方根误差(RMSE)会和statsmodels.OLS的结果完全一致。这是因为两者都是基于普通最小二乘法(OLS)拟合线性模型,回归系数完全相同,只要残差计算正确,结果自然匹配。

内容的提问来源于stack exchange,提问作者Hasek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:37:03