我在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
答案 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_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.希望我很清楚。