我想为 future 选择最好的算法。我找到了一些解决方案,但我不明白哪个 R-Squared 值是正确的。
为此,我将我的数据分为测试和训练两部分,并在下面打印了两个不同的 R 平方值。
import statsmodels.api as sm
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
lineer = LinearRegression()
lineer.fit(x_train,y_train)
lineerPredict = lineer.predict(x_test)
scoreLineer = r2_score(y_test, lineerPredict) # First R-Squared
model = sm.OLS(lineerPredict, y_test)
print(model.fit().summary()) # Second R-Squared
第一个 R 平方结果是 -4.28。
第二个 R 平方结果是 0.84
但我不明白哪个值是正确的。
请您参考如下方法:
可以说,在这种情况下,真正的挑战是确保将苹果与苹果进行比较。在你的情况下,你似乎没有。我们最好的 friend 总是相关的文档,结合简单的实验。所以...
虽然 scikit-learn 的 LinearRegression() (即您的第一个 R 平方)默认使用 fit_intercept=True 拟合( docs ), 这是 不是 statsmodels 的案例 OLS (你的第二个 R 平方);引自 docs :
An intercept is not included by default and should be added by the user. See
statsmodels.tools.add_constant.
记住这个重要的细节,让我们用虚拟数据运行一些简单的实验:
import numpy as np
import statsmodels.api as sm
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
# dummy data:
y = np.array([1,3,4,5,2,3,4])
X = np.array(range(1,8)).reshape(-1,1) # reshape to column
# scikit-learn:
lr = LinearRegression()
lr.fit(X,y)
# LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None,
# normalize=False)
lr.score(X,y)
# 0.16118421052631582
y_pred=lr.predict(X)
r2_score(y, y_pred)
# 0.16118421052631582
# statsmodels
# first artificially add intercept to X, as advised in the docs:
X_ = sm.add_constant(X)
model = sm.OLS(y,X_) # X_ here
results = model.fit()
results.rsquared
# 0.16118421052631593
出于所有实际目的,由 scikit-learn 和 statsmodels 生成的这两个 R 平方值是
相同 .
让我们更进一步,尝试一个没有拦截的 scikit-learn 模型,但我们使用人工“拦截”的数据
X_我们已经构建用于 statsmodels:
lr2 = LinearRegression(fit_intercept=False)
lr2.fit(X_,y) # X_ here
# LinearRegression(copy_X=True, fit_intercept=False, n_jobs=None,
# normalize=False)
lr2.score(X_, y)
# 0.16118421052631593
y_pred2 = lr2.predict(X_)
r2_score(y, y_pred2)
# 0.16118421052631593
同样,R 平方是
相同 与以前的值。
那么,当我们“不小心”忘记考虑 statsmodels
OLS 的事实时会发生什么?安装没有拦截?让我们来看看:
model3 = sm.OLS(y,X) # X here, i.e. no intercept
results3 = model2.fit()
results3.rsquared
# 0.8058035714285714
好吧,0.80 的 R 平方确实与具有截距的模型返回的 0.16 相距甚远,可以说这正是您的情况所发生的情况。
到目前为止一切顺利,我可以在这里轻松完成答案;但是这个和谐的世界确实有一个问题:让我们看看当我们在没有截距和初始数据的情况下拟合两个模型时会发生什么
X我们没有人为地添加任何拦截。我们已经安装了
OLS上面的模型,得到了 0.80 的 R 平方;来自 scikit-learn 的类似模型怎么样?
# scikit-learn
lr3 = LinearRegression(fit_intercept=False)
lr3.fit(X,y) # X here
lr3.score(X,y)
# -0.4309210526315792
y_pred3 = lr3.predict(X)
r2_score(y, y_pred3)
# -0.4309210526315792
哎呀……!有没有搞错??
似乎 scikit-earn,当计算
r2_score 时, 始终假设截距,无论是在模型中显式(
fit_intercept=True )还是在数据中隐式(我们使用 statsmodels 的
X_ 从上面的
X 生成
add_constant 的方式);在网上挖了一点发现
Github thread (无补救措施关闭)在确认情况确实如此的情况下。
让我澄清一下,我上面描述的差异有 没什么与您的问题有关:就您而言,真正的问题是您实际上是在将苹果(具有截距的模型)与橙子(没有截距的模型)进行比较。
那么,为什么 scikit-learn 不仅在这种(无可否认的边缘)情况下失败,而且即使事实出现在 Github 问题中,它实际上也被冷漠对待? (另请注意,在上述帖子中回复的 scikit-learn 核心开发人员随便承认“我对统计数据不是很熟悉”......)。
答案有点超出编码问题,例如 SO 主要涉及的问题,但在这里可能值得详细说明。
可以说,原因是整个 R 平方概念实际上直接来自统计领域,重点是解释模型,而在机器学习环境中几乎没有用,因为机器学习的重点显然是预测模型;至少 AFAIK,除了一些非常介绍性的类(class),我从来没有(我的意思是从来没有......)看到预测建模问题,其中 R 平方用于任何类型的性能评估;流行的机器学习介绍也不是偶然的,例如 Andrew Ng 的 Machine Learning在 Coursera 上,甚至都懒得提。而且,如上面 Github 线程中所述(强调):
In particular when using a test set, it's a bit unclear to me what the R^2 means.
我当然同意这一点。
至于上面讨论的边缘情况(包括或不包括拦截项?),我怀疑这听起来与现代深度学习从业者真的无关,在神经网络模型中默认情况下总是包含拦截的等价物(偏差参数) ...
请参阅交叉验证问题 Difference between statsmodel OLS and scikit linear regression 中已接受(并高度赞成)的答案沿着这些最后几行进行更详细的讨论。 Is R-squared Useless? 中的讨论(和链接)由伟大的统计学家 Cosma Shalizi 的一些相关(负面)评论引发的,也很有启发性,强烈推荐。
