【问题标题】:Significant mismatch between `r2_score` of `scikit-learn` and the R^2 calculation`scikit-learn` 的 `r2_score` 与 R^2 计算显着不匹配
【发布时间】:2016-01-30 09:33:58
【问题描述】:

问题

为什么r2_score function in scikit-learnCoefficient of Determination as described in Wikipedia 的公式之间存在显着差异?哪个是正确的?


上下文

我使用 Python 3.5 来预测线性和二次模型,我正在尝试的拟合优度度量之一是 .但是,在测试时,scikit-learn 中的 r2_score 指标与 Wikipedia 中提供的计算之间存在显着差异。


代码

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

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

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

谢谢!

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

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

【问题讨论】:

  • 我认为您提到的问题没有正确回答我的问题。没有提到两个来源的结果之间的差异,这是我的问题试图解决的要点。事实上,scikit-learn 中的计算是否有效是一个非常重要的点(以及为什么),我认为应该确定以备将来参考。跨度>

标签: python numpy scikit-learn goodness-of-fit


【解决方案1】:

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

【讨论】:

  • 那么,基本上,维基百科答案中给出的结果是不正确的?
  • @JuanCarlosCoto 不,维基百科是正确的。维基百科文章指出,与给定 x-y 数据拟合的线性最小二乘法的 R^2 为 0.998。那里给出的数据不是yf。有关更多信息,请参阅我的答案。
【解决方案2】:

我认为您误解了维基百科。维基百科上的示例确实声明:

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 来找到最小二乘拟合,然后使用这两种方法来找到两者都为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

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

      【解决方案4】:

      两种方法都使用相同的公式来计算 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

      【讨论】:

        【解决方案5】:

        两者都是正确的。问题是 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 接近于零。

        【讨论】:

          猜你喜欢
          • 2016-11-28
          • 2018-05-26
          • 2017-08-01
          • 2018-07-14
          • 1970-01-01
          • 2022-01-20
          • 2021-11-03
          • 2014-05-11
          • 2014-09-27
          相关资源
          最近更新 更多