“scikit learn”的“r2_score”与R^2计算之间的严重不匹配

2024-05-11 08:31:31 发布

您现在位置:Python中文网/ 问答频道 /正文

问题

为什么^{} function in scikit-learnCoefficient of Determination as described in Wikipedia的公式之间有显著差异?哪个是正确的?


上下文

我使用Python3.5来预测线性和二次模型,我正在尝试的拟合优度度量之一是。然而,在测试时,scikit-learn中的r2_score度量与Wikipedia中提供的计算有显著的区别。


代码

我在这里提供我的代码作为参考,它计算上面链接的维基百科页面中的示例。

from sklearn.metrics import r2_score
import numpy

y = [1, 2, 3, 4, 5]
f = [1.9, 3.7, 5.8, 8.0, 9.6]

# Convert to numpy array and ensure double precision to avoid single precision errors
observed = numpy.array(y, dtype=numpy.float64)
predicted = numpy.array(f, dtype=numpy.float64)

scipy_value = r2_score(observed, predicted)

>>> scipy_value: 

很明显,scipy计算值是-3.8699999999999992,而Wikipedia中的参考值是0.998

谢谢你!

更新:这与this question about how R^2 is calculated in scikit-learn不同,因为我试图理解并澄清的是两个结果之间的差异。这个问题说明scikit中使用的公式与Wikipedia中使用的公式相同,不应导致不同的值。

更新#2:结果我在阅读维基百科文章的示例时出错。下面的回答和评论提到,我提供的示例是示例中(x,y)值的线性最小二乘拟合。为此,维基百科文章中的答案是正确的。为此,提供的R^2计算值为0.998。对于两个向量之间的R^2,scikit的答案也是正确的。非常感谢你的帮助!


Tags: 代码innumpy示例度量线性scipy差异
3条回答

确定系数有效地将数据中的方差与残差中的方差进行比较。残差是预测值和观测值之间的差,其方差是该差的平方和。

如果预测是完美的,残差的方差为零。因此,确定系数是1。如果预测结果不理想,则残差部分为非零,残差方差为正。因此,确定系数小于1。

显然,玩具问题的决定系数很低,因为大多数预测值都相差很远。测定-3.86的系数意味着残差的方差是观测值方差的4.86倍。

0.998值来自数据集的线性最小二乘拟合的确定系数。这意味着观测值与预测值之间通过一个线性关系(加上一个常数)进行关联,该线性关系将残差的方差最小化。玩具问题的观测值和预测值具有高度的线性相关性,因此线性最小二乘拟合的确定系数非常接近于1。

我认为你误解了维基百科。维基百科上的例子并没有说明:

y=[1,2,3,4,5]
f=[1.9, 3.7, 5.8, 8.0, 9.6]
R^2 = 0.998

相反,它说线性最小二乘的R^2适合于数据:

x=[1,2,3,4,5]
y=[1.9, 3.7, 5.8, 8.0, 9.6]

等于0.998

考虑一下这个脚本,它首先使用^{}来找到最小二乘拟合,然后使用这两种方法来为这两种情况找到0.998的R^2

import numpy as np
from sklearn.metrics import r2_score

x=np.arange(1,6,1)
y=np.array([1.9, 3.7, 5.8, 8.0, 9.6])

A=np.vstack([x, np.ones(len(x))]).T

# Use numpy's least squares function
m, c = np.linalg.lstsq(A, y)[0]

print m,c
# 1.97 -0.11

# Define the values of our least squares fit
f=m*x+c

print f
# [ 1.86  3.83  5.8   7.77  9.74]

# Calculate R^2 explicitly
yminusf2=(y-f)**2
sserr=sum(yminusf2)
mean=float(sum(y))/float(len(y))
yminusmean2=(y-mean)**2
sstot=sum(yminusmean2)
R2=1.-(sserr/sstot)

print R2
# 0.99766066838

# Use scikit
print r2_score(y,f)
# 0.99766066838

r2_score(y,f) == R2
# True

所提到的问题是正确的——如果您计算剩余平方和和和平方和,您得到的值与sklearn相同:

In [85]: import numpy as np

In [86]: y = [1,2,3,4,5]

In [87]: f = [1.9, 3.7, 5.8, 8.0, 9.6]

In [88]: SSres = sum(map(lambda x: (x[0]-x[1])**2, zip(y, f)))

In [89]: SStot = sum([(x-np.mean(y))**2 for x in y])

In [90]: SSres, SStot
Out[90]: (48.699999999999996, 10.0)

In [91]: 1-(SSres/SStot)
Out[91]: -3.8699999999999992

负值背后的想法是,如果你只是预测了每次的平均值(这将对应于r2=0),你就会更接近实际值。

相关问题 更多 >