【问题标题】:Scikit-learn is returning coefficient of determination (R^2) values less than -1Scikit-learn 正在返回小于 -1 的决定系数 (R^2) 值
【发布时间】:2014-05-27 01:00:24
【问题描述】:

我正在做一个简单的线性模型。我有

fire = load_data()
regr = linear_model.LinearRegression()
scores = cross_validation.cross_val_score(regr, fire.data, fire.target, cv=10, scoring='r2')
print scores

产生

[  0.00000000e+00   0.00000000e+00  -8.27299054e+02  -5.80431382e+00
  -1.04444147e-01  -1.19367785e+00  -1.24843536e+00  -3.39950443e-01
   1.95018287e-02  -9.73940970e-02]

这怎么可能?当我对内置的糖尿病数据做同样的事情时,它工作得非常好,但是对于我的数据,它返回了这些看似荒谬的结果。我做错了什么吗?

【问题讨论】:

  • 要让LinearRegression 发生这种情况,您的模型必须非常糟糕,以至于每次都预测一个简单的平均值会更好。通常这意味着您的模型过度拟合。有关详细信息,请参阅下面的答案,或尝试将 cv 设置为较小的数字。

标签: python statistics scikit-learn


【解决方案1】:

没有理由r^2 不应该是负数(尽管名称中有^2)。这也在doc 中说明。您可以将r^2 视为您的模型拟合(在线性回归的上下文中,例如 1 阶(仿射)模型)与 0 阶模型(仅拟合常数)的比较,均通过最小化平方损失.最小化平方误差的常数是平均值。由于您正在使用遗漏数据进行交叉验证,因此测试集的平均值可能与训练集的平均值大不相同。与仅预测测试数据的平均值相比,仅此一项可能会在您的预测中产生更高的平方误差,从而导致r^2 得分为负。

在最坏的情况下,如果您的数据根本无法解释您的目标,那么这些分数可能会变得非常负面。试试

import numpy as np
rng = np.random.RandomState(42)
X = rng.randn(100, 80)
y = rng.randn(100)  # y has nothing to do with X whatsoever
from sklearn.linear_model import LinearRegression
from sklearn.cross_validation import cross_val_score
scores = cross_val_score(LinearRegression(), X, y, cv=5, scoring='r2')

这应该会产生负的r^2 值。

In [23]: scores
Out[23]: 
array([-240.17927358,   -5.51819556,  -14.06815196,  -67.87003867,
    -64.14367035])

现在的重要问题是,这是由于线性模型在您的数据中找不到任何东西,还是由于在数据预处理中可能修复的其他问题。您是否尝试过将列缩放为均值 0 和方差 1?您可以使用sklearn.preprocessing.StandardScaler 执行此操作。事实上,您应该通过使用sklearn.pipeline.PipelineStandardScalerLinearRegression 连接到管道中来创建一个新的估计器。 接下来,您可能想尝试 Ridge 回归。

【讨论】:

  • 感谢您的帮助。我知道 R^2 可以是负数,但我认为它应该限制在区间 [-1, 1] 内。不是这样吗?
  • R^2 以 1.0 为界,但不以 1.0 为界。 相关性始终介于 -1 和 1 之间。
  • 仅仅因为R^2 可以是负数,并不意味着我们应该期望它是负数。请在下面查看我的回答,了解R^2 可能是否定的原因以及如何解决它们。
【解决方案2】:

R² = 1 - RSS / TSS,其中 RSS 是残差平方和 ∑(y - f(x))²,TSS 是平方和总和 ∑(y - mean(y))²。现在对于 R² ≥ -1,要求 RSS/TSS ≤ 2,但很容易构建一个模型和数据集,而这不正确:

>>> x = np.arange(50, dtype=float)
>>> y = x
>>> def f(x): return -100
...
>>> rss = np.sum((y - f(x)) ** 2)
>>> tss = np.sum((y - y.mean()) ** 2)
>>> 1 - rss / tss
-74.430972388955581

【讨论】:

  • 没错,模型只要“够错”就好了,如果你选择完全不对应的东西,这并不难。
【解决方案3】:

R^2 可以是负数并不意味着它应该是。

可能性 1:代码中的错误。

您应该仔细检查的一个常见错误是您正确地传递了参数:

r2_score(y_true, y_pred) # Correct!
r2_score(y_pred, y_true) # Incorrect!!!!

可能性 2:小数据集

如果你得到一个负的 R^2,你也可以检查是否过度拟合。请记住,cross_validation.cross_val_score() 不会随机打乱您的输入,因此如果您的样本被无意中排序(例如按日期),那么您可能会在每个折叠上构建模型,而不能预测其他折叠。

尝试减少特征数量、增加样本数量和减少折叠数量(如果您使用的是cross_validation)。虽然这里没有官方规定,但您的 m x n 数据集(其中 m 是样本数,n 是特征数)的形状应该是

m > n^2

当你使用f作为折叠数的交叉验证时,你应该瞄准

m/f > n^2

【讨论】:

  • 寻找错误的好方法。负 R^2 绝对值得研究!然而,即使你做对了所有事情,R^2 仍然可能是纯随机性的负数。事实上,使用线性预测器在高斯噪声(即预测器无法预测的数据)上的预测 R^2 的零分布是负的。 (估计的平均值是错误的,即不为 ​​0,斜率也几乎肯定不为 0)
  • @eickenberg 是的,但我相信在大多数情况下它会略微消极。我真正找到这个问题的原因是因为我得到了大约-0.99R^2,结果我只是简单地翻转了r2_score 中的y_true 和y_pred。我想很多用户都会遇到类似的愚蠢错误。
  • 是的,有趣的观察!实际上,如果预测的方差小于目标(如果涉及例如加性噪声,通常就是这种情况),这将使 R^2 任意降低。很高兴把这个写在这里,它可以导致很多人花更少的时间处理这种类型的错误。
  • R^2 为负数。这是此处发布的反转参数问题,并且在修复 R^2 之后是有意义的。我一直在绘制图表,这些图表显示出明显的关系,所以我摸不着头脑。谢谢!
【解决方案4】:

如果您得到负回归 r^2 分数,请确保在对模型进行拟合/评分之前从数据集中删除任何唯一标识符(例如“id”或“rownum”)。简单的检查,但它会为您节省一些头痛的时间。

【讨论】:

    猜你喜欢
    • 2016-08-09
    • 2018-10-20
    • 2017-03-26
    • 2021-03-02
    • 2014-04-14
    • 2020-06-20
    • 2020-09-12
    • 1970-01-01
    相关资源
    最近更新 更多