为啥 `sklearn` 和 `statsmodels` 的 OLS 回归实现给出不同的 R^2?

Posted

技术标签:

【中文标题】为啥 `sklearn` 和 `statsmodels` 的 OLS 回归实现给出不同的 R^2?【英文标题】:Why `sklearn` and `statsmodels` implementation of OLS regression give different R^2?为什么 `sklearn` 和 `statsmodels` 的 OLS 回归实现给出不同的 R^2? 【发布时间】:2018-07-27 17:25:25 【问题描述】:

我偶然注意到,sklearnstatsmodels 实现的 OLS 模型在不拟合截距时会产生不同的 R^2 值。否则,它们似乎工作正常。以下代码产生:

import numpy as np
import sklearn
import statsmodels
import sklearn.linear_model as sl
import statsmodels.api as sm

np.random.seed(42)

N=1000
X = np.random.normal(loc=1, size=(N, 1))
Y = 2 * X.flatten() + 4 + np.random.normal(size=N)

sklernIntercept=sl.LinearRegression(fit_intercept=True).fit(X, Y)
sklernNoIntercept=sl.LinearRegression(fit_intercept=False).fit(X, Y)
statsmodelsIntercept = sm.OLS(Y, sm.add_constant(X))
statsmodelsNoIntercept = sm.OLS(Y, X)

print(sklernIntercept.score(X, Y), statsmodelsIntercept.fit().rsquared)
print(sklernNoIntercept.score(X, Y), statsmodelsNoIntercept.fit().rsquared)

print(sklearn.__version__, statsmodels.__version__)

打印:

0.78741906105 0.78741906105
-0.950825182861 0.783154483028
0.19.1 0.8.0

差异从何而来?

这个问题与Different Linear Regression Coefficients with statsmodels and sklearn 不同,因为sklearn.linear_model.LinearModel(带截距)适用于为statsmodels.api.OLS 准备的X。

问题不同于 Statsmodels: Calculate fitted values and R squared 因为它解决了两个 Python 包(statsmodelsscikit-learn)之间的差异,而链接的问题是关于 statsmodels 和常见的 R^2 定义。他们都得到了相同的答案,但是这个问题已经在这里讨论过:Does the same answer imply that the questions should be closed as duplicate?

【问题讨论】:

什么意思? -0.72... 与 0.78... 完全不同... 始终播种随机数据以获得可重复性:np.random.seed(###). 没有截距会改变 statsmodels 中 R2 的定义。见***.com/questions/29664471/… 和***.com/questions/24851787/… @Parfait 同意了。在这种特殊情况下,我省略了种子,因为样本非常大,并且每次运行的结果都不同。但是为了正确起见,我更新了示例。 @user333700 你可以给出这个答案吗?我愿意接受。 【参考方案1】:

正如 cmets 中的 @user333700 所指出的,statsmodels' 实现中 R^2 的 OLS 定义与 scikit-learn's 中的不同。

来自documentation of RegressionResults class(强调我的):

平方

具有截距的模型的 R 平方。这在这里定义为 1 - s-s-r/centered_tss 如果常量包含在模型中并且 1 - s-s-r/uncentered_tss 如果常量被省略.

来自documentation of LinearRegression.score()

score(X, y, sample_weight=None)

返回系数 确定预测的R^2。

系数R^2定义为(1 - u/v),其中u为残差

平方和 ((y_true - y_pred) ** 2).sum() 和 v 是总和 平方数 ((y_true - y_true.mean()) ** 2).sum()。最好的 score 是 1.0,它可以是负数(因为模型可以 任意更坏)。始终预测预期的常数模型 y 的值,忽略输入特征,将得到 R^2 分数 0.0.

【讨论】:

以上是关于为啥 `sklearn` 和 `statsmodels` 的 OLS 回归实现给出不同的 R^2?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 sklearn 逻辑回归正则化权重和截距?

为啥 `sklearn` 和 `statsmodels` 的 OLS 回归实现给出不同的 R^2?

为啥 sklearn 和 numpy 不同意 PCA 的乘法分量?

为啥 auc 与 sklearn 和 R 的逻辑回归如此不同

为啥我在 python 的 sklearn 中使用管道和没有管道得到不同的值

为啥 CPU(使用 SKLearn)和 GPU(使用 RAPID)上的 RandomForestClassifier 获得不同的分数,非常不同?