“scikit learn”的“r2_score”与R^2计算之间存在显著不匹配



问题

为什么scikit learn中的r2_score函数与维基百科中描述的决定系数公式之间存在显著差异?哪个是正确的?


上下文

我使用Python 3.5来预测线性和二次模型,我正在尝试的拟合优度度量之一是。然而,在测试时,scikit-learn中的r2_score度量与维基百科中提供的计算之间存在显著差异。


代码

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

从sklearn.metrics导入r2_score导入numpyy=[1,2,3,4,5]f=[1.9,3.7,5.8,8.0,9.6]#转换为numpy数组并确保双精度以避免单精度错误observed=numpy.array(y,dtype=numpy.foat64)predicted=numpy.array(f,dtype=numpy.foat64)scipy_value=r2_score(观测到、预测到)>>>scipy_value(_V):

很明显,scipy的计算值是-3.8699999999999992,而维基百科中的参考值是0.998

谢谢!

更新:这与关于如何在scikit中计算R^2的问题不同,因为我试图理解并澄清的是两个结果之间的差异。这个问题表明scikit中使用的公式与维基百科的公式相同,不应导致不同的值。

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

我认为你误解了维基百科。维基百科上的例子是而不是状态:

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

参考的问题是正确的——如果你计算残差平方和和平方和,你会得到与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),你会更接近实际值。

两种方法都使用相同的公式来计算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.9976606683804627R-Sqaure(得分):0.9976606683804627

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

如果预测是完美的,则残差的方差为零。因此,决定系数为1。如果预测不是完美的,则一些残差是非零的,并且残差的方差是正的。因此,决定系数低于1。

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

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

两者都是正确的。问题是scikit learn直接在数据上使用R2的方程。

y=[1,2,3,4,5]

f=[1.9,3.7,5.8,8.0,9.6]

Scikit学习计算SSR和SST,考虑y是真值,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_prd=[1.86,3.83,5.8,7.77,9.74]

如果使用f和f_pred数据的方程(1-SSR/SST):

SSR=SUM[(f-fp_pred)^2]=SUM[00016、0.0169、0.0529、0.0196、0.091]=0.091

SST=总和[(f-AVE(f))^2]=总和[15.21,4.41,4.84,14.44,38.9]=38.9

R2=(1-0.091/38.9)=0.998

scikit学习中的负R2意味着你的模型比观察到的列车数据的平均值更差。负R2尤其发生在测试数据中,因为它们不参与拟合建模。当你在scikit学习中有一个负的R2值时,使用True和Pred值之间的线性回归R2,你的R2将接近零。

相关内容

  • 没有找到相关文章

最新更新