Scikit-Learn给出不正确的R Squared值

时间:2017-07-14 13:23:26

标签: python python-3.x scikit-learn statistics

我在Python上训练机器学习模型,并使用Scikit Learn的R平方指标来评估它们。 Id决定使用Scikit的r2_score函数,为它提供一个与输入y_true相同值的随机数组,并且与y_predict略有不同但相同的值数组。当数组的输入长度为10或更大时,我得到任意大(负)值,当输入长度小于10时,我得到0。

from sklearn.metrics import r2_score
r2_score([213.91666667,  213.91666667,  213.91666667,  213.91666667,  213.91666667, 
      213.91666667, 213.91666667,  213.91666667,  213.91666667,  213.91666667],
    [213,  214,  214,  214,  214,  214,  214,  214,  214,  214])

>>> -1.1175847590636849e+26

r2_score([213.91666667,  213.91666667,  213.91666667,  213.91666667, 
      213.91666667, 213.91666667,  213.91666667,  213.91666667,  213.91666667],
    [213,  214,  214,  214,  214,  214,  214,  214,  214])

>>> 0

3 个答案:

答案 0 :(得分:1)

您注意到r2_score输出不正确。但是,这是计算问题更简单的结果,而不是scikit-learn包的问题。

尝试运行

>>> input_list = [213.91666667,  213.91666667,  213.91666667,  213.91666667,  213.91666667, 
  213.91666667, 213.91666667,  213.91666667,  213.91666667,  213.91666667]
>>> sum(input_list)/len(input_list)

如您所见,输出不完全是213.91666667(有限精度错误;您可以阅读更多关于它here)。为什么这很重要?

嗯,scikit-learn User Guide的部分给出了用于计算r2_score的具体公式:

r2 formula

如您所见,r2_score只是1 - (残差平方和)/(平方和)。

在你指定的第一种情况下,剩余的平方和等于某个数字... ...并不重要。你可以很容易地计算出来;它大约是0.09,看起来并不高。但是,由于上面描述的浮点误差,总平方和并不是0,而是一些非常非常小的数字(想想大约10 ^ -28 - 非常小)。

因此,当你将残差平方和(大约0.09)除以总平方和(非常小的数字)时,你会留下一个非常大的数字。由于从1中减去了这个较大的数字,因此您的r2_score输出将保留一个较高的负数。

在第二种情况下,计算总平方和的这种不精确性不会发生,因此分母为0,并且从计算中看到未定义值的函数应返回0.

答案 1 :(得分:0)

这与scikit学习无关,而是与R ^ 2本身的概念有关。 直觉上,您可以将其视为解释变量X解释的Y的方差比率。

这里X方差为零(你总是重复相同的数字),因此R ^ 2为零(当两个向量具有相同的长度时)。

如果这两个向量具有不同的长度......那么回归本身并没有很好地定义。我想如果函数返回错误会更好。

答案 2 :(得分:0)

查看source code of r2_score,我们可以看到以下行(指定了默认权重)

weight = 1
sample_weight = None

y_true = np.array([213.91666667,  213.91666667,  213.91666667,  213.91666667,    213.91666667, 213.91666667, 213.91666667,  213.91666667,  213.91666667,  213.91666667]).reshape(-1,1)

y_pred = np.array([213,  214,  214,  214,  214,  214,  214,  214,  214,  214]).reshape(-1,1)

numerator = (weight * (y_true - y_pred) ** 2).sum(axis=0,
                                                  dtype=np.float64)
denominator = (weight * (y_true - np.average(
    y_true, axis=0, weights=sample_weight)) ** 2).sum(axis=0,
                                                      dtype=np.float64)
nonzero_denominator = denominator != 0
nonzero_numerator = numerator != 0
valid_score = nonzero_denominator & nonzero_numerator
output_scores = np.ones([y_true.shape[1]])
output_scores[valid_score] = 1 - (numerator[valid_score] /
                                  denominator[valid_score])

return np.average(output_scores, weights=None)

您案例中有问题的行是denominator计算。

对于第一种情况:

denominator = (weight * (y_true - np.average(
    y_true, axis=0, weights=sample_weight)) ** 2).sum(axis=0,
                                                      dtype=np.float64)

print(denominator)

[  8.07793567e-27]

它非常小,但不是0。

对于第二种情况:其为0。

由于分母为0,因此r2_score未定义并返回0.希望我很清楚。