Statsmodels:计算拟合值和R方

11 投票
2 回答
20455 浏览
提问于 2025-04-18 14:01

我正在进行回归分析,代码如下(df 是一个 pandas 数据框):

import statsmodels.api as sm
est = sm.OLS(df['p'], df[['e', 'varA', 'meanM', 'varM', 'covAM']]).fit()
est.summary()

这个分析给了我一个 R-squared 值为 0.942。接下来,我想把原始的 y-values 和拟合值画出来。为此,我对原始值进行了排序:

orig = df['p'].values
fitted = est.fittedvalues.values
args = np.argsort(orig)
import matplotlib.pyplot as plt
plt.plot(orig[args], 'bo')
plt.plot(orig[args]-resid[args], 'ro')
plt.show()

但是,这样得到的图表显示的值完全不对,根本没有任何迹象表明 R-squared 会是 0.9。所以,我尝试自己手动计算一下:

yBar = df['p'].mean()
SSTot = df['p'].apply(lambda x: (x-yBar)**2).sum()
SSReg = ((est.fittedvalues - yBar)**2).sum()  
1 - SSReg/SSTot
Out[79]: 0.2618159806908984

我是不是做错了什么?或者说有什么原因导致我计算的结果和 statsmodels 得到的结果差距这么大?SSTotSSReg 的值分别是 4808435495

2 个回答

5

如果你的模型是:

a = <yourmodel>.fit()

那么,要计算拟合值(也就是模型预测的结果):

a.fittedvalues

并且要计算R平方值(用来衡量模型的好坏):

a.rsquared
13

如果你在模型中不加入一个常数项(也就是一个固定的解释变量),statsmodels会根据未中心化的总平方和来计算R平方值,也就是说:

tss = (ys ** 2).sum()  # un-centred total sum of squares

与之相对的是

tss = ((ys - ys.mean())**2).sum()  # centred total sum of squares

因此,R平方值会高很多。

从数学上来说,这样做是正确的。因为,R平方值应该表示完整模型与简化模型相比,解释了多少变化。如果你把模型定义为:

ys = beta1 . xs + beta0 + noise

那么简化模型可以是:ys = beta0 + noise,其中beta0的估计值是样本的平均值,因此我们有:noise = ys - ys.mean()。这就是在有常数项的模型中,为什么会有去均值的过程。

但是对于像这样的模型:

ys = beta . xs + noise

你可能只能简化为:ys = noise。因为noise被假设为零均值,所以你不能对ys进行去均值处理。因此,在简化模型中,未解释的变化就是未中心化的总平方和。

这方面的详细信息可以在这里找到,查看rsquared项。将yBar设置为零,我预计你会得到相同的结果。

撰写回答