为什么r2_score
function in scikit-learn和Coefficient of Determination as described in Wikipedia的公式之间存在显着差异?哪个是正确的?
我正在使用Python 3.5来预测线性和二次模型,而我正在尝试的适合度的衡量标准之一就是。但是,在测试时,r2_score
中的scikit-learn
指标与维基百科中提供的计算之间存在显着差异。
我在这里提供我的代码作为参考,它计算上面链接的维基百科页面中的示例。
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
,而维基百科中的参考值为0.998
。
谢谢!
更新:这与this question about how R^2 is calculated in scikit-learn不同,因为我正在努力理解并澄清两种结果之间的差异。这个问题表明scikit中使用的公式与维基百科的公式相同,不应该产生不同的值。
更新#2:事实证明,我在阅读维基百科文章的例子时犯了一个错误。下面的答案和评论提到我提供的示例是针对示例中(x,y)值的线性,最小二乘拟合。为此,维基百科的文章中的答案是正确的。为此,提供的R ^ 2 calue为0.998。对于两个向量之间的R ^ 2,scikit的答案也是正确的。非常感谢你的帮助!
答案 0 :(得分:6)
引用的问题是正确的 - 如果你通过计算剩余的平方和和总平方和,你会得到与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),您就更接近实际值。
答案 1 :(得分:4)
我认为你误解了维基百科。维基百科上的示例执行 不 状态:
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
考虑这个脚本,它首先使用np.linalg.lstsq
来找到最小二乘拟合,并使用两种方法为两者找到R^2
0.998:
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
答案 2 :(得分:1)
确定系数有效地将数据中的方差与残差中的方差进行比较。残差是预测值和观测值之间的差值,其方差是这种差值的平方和。
如果预测是完美的,则残差的方差为零。因此,确定系数是一。如果预测不完美,则一些残差是非零的,并且残差的方差是正的。因此,确定系数低于1。
玩具问题显然具有较低的决心系数,因为大多数预测值都是偏离的。 -3.86
的确定系数意味着残差的方差是观察值的方差的4.86
倍。
0.998
值来自该组数据的线性最小二乘拟合的确定系数。这意味着观测值通过线性关系(加上常数)与预测值相关,最小化残差的方差。玩具问题的观测值和预测值是高度线性相关的,因此线性最小二乘拟合的确定系数非常接近1。
答案 3 :(得分:0)
两种方法都使用相同的公式来计算R平方。查看下面的代码:
# Data
X=np.array([1.9, 3.7, 5.8, 8.0, 9.6]).reshape(-1, 1)
y=[1,2,3,4,5]
# Import module
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
reg = LinearRegression().fit(X, y)
# Predict the target variable
y_pred=reg.predict(X)
# R-Square fitness
print('R-Square(metrics):', r2_score(y, y_pred))
# R-Square using score method
print('R-Sqaure(Score):',reg.score(X, y))
输出: R平方(度量):0.9976606683804627 R-Sqaure(分数):0.9976606683804627
答案 4 :(得分:0)
两者都对。问题是 scikit learn 直接在数据上使用了 R2 的方程。
y = [1, 2, 3, 4, 5]
f = [1.9, 3.7, 5.8, 8.0, 9.6]
Scikit learn 计算 SSR 和 SST,考虑 y 是 True 值,f 是 y 的预测。
维基百科使用 y 作为特征数组 (x),而 f 是您需要预测的人 (y)。所以有一个回归变成 f_pred = 1.97y + 0.11。所以,现在你有了 f 的真实值和 f 的 f_pred。 R2 在它们之间计算。
y = [1, 2, 3, 4, 5]
f = [1.9, 3.7, 5.8, 8.0, 9.6]
f_pred = [1.86, 3.83, 5.8, 7.77, 9.74]
如果您使用使用 f 和 f_pred 数据的等式 (1- SSR/SST):
SSR = SUM[(f-fp_pred)^2] = SUM[0.0016, 0.0169, 0.0529, 0.0196, 0.091] = 0.091
SST = SUM[(f-AVE(f))^2] = SUM[15.21, 4.41, 4.84, 14.44, 38.9] = 38.9
R2 = (1-0.091/38.9) = 0.998
scikit learn 中的负 R2 意味着您的模型比观察到的训练数据的平均值更差。负 R2 尤其发生在测试数据中,因为它们不参与拟合建模。当 scikit learn 中的 R2 值为负时,使用 True 和 Pred 值之间的线性回归的 R2 将使 R2 接近于零。