15-评价回归算法 R Square

  在上一篇博客中,介绍了评价回归算法的优劣这样的三个指标:MSE,RMSE,MAE。其实这些指标还有它的问题。回忆一下,我们在学习分类问题的时候,我们评价分类问题的指标非常的简单,就是分类的准确度(accuracy),对于分类的准确度来说,它的取值是在0-1之间的,如果是1,代表它的分类准确度是百分百准确的,是最好的,如果是0,是最差的,这个评价标准是非常清晰的,因为分类的准确度就是在0-1之间取值,即使我们分类的问题不同,我们也可以很容易的比较它们之间的优劣。

  但是 RMSE 和 MAE 是没有这样的性质的。比如说可能我预测的是房产数据,最后得到的 RMSE 也好,MAE 也好,它们的值是5,意思是说我们的误差是5万元,而我们预测学生的成绩可能预测的误差是10,也就是预测的差距是10分,那么在这种情况下,请问我们的算法是作用在预测房产中好呢?还是使用在预测学生成绩中好呢?我们是无法判断的。这是因为这个5和10对应的是不同种类的东西,我们无法直接比较。这就是我们使用的 RMSE 和 MAE 的局限性。

  那么这个问题是可以解决的。解决的方法是使用一个新的指标:R Squared,通常在中文中我们也可以叫做 R 方。用以下式子计算:
在这里插入图片描述
  看到这里,先不要晕。看下面这个式子:
在这里插入图片描述
  相信列出了这样一个式子,我们就已经可以编程来实现计算这个 R 方了。

  但是,我想更深入的了解一下 R方 这个指标它的意义是什么?它为什么好?
在这里插入图片描述
那么我们再来看看 R 方的计算结果,我们会得到以下结论:

  • R^2 <= 1
  • R^2 越大越好。当我们的预测模型不犯任何错误时,R^2 得到最大值 1
  • 当我们的模型等于基准模型(Baseline Model)时,R^2 为 0
  • 如果 R^2 < 0,说明我们学习到的模型还不如基准模型。此时,很有可能我们的数据不存在任何线性关系。

  所以我们使用 R^2 有一个非常重要的优势,相当于把回归问题最终的这个衡量结果也归约到了0-1之间,1 是最好的,0 是最差的。那么在这样的情况下,我们可以非常方便的使用这个指标来针对同一个回归算法应用在不同的问题上最终得到的结果来进行一个比较。不过,我们这个R方和分类问题使用的准确度有非常大的不同,就是存在R方小于0的情况。如果R方小于0,意味着我们模型得到的错误是大于我们使用基准模型得到的错误的,这意味着什么?意味着我们训练了半天我们的模型还不如不训练它呢,我们直接使用基准模型预测的结果都比我们训练出的模型预测的结果还要好。那么在这种情况下,R方就会小于0。其实我们在处理真实数据的时候,有可能会遇到R方小于0的这种情况,如果遇到这种情况就需要小心了,它说明你训练的这个模型实在是太差了,还不如直接使用基准模型。那么在这种情况下,通常很有可能意味着你的数据根本不存在线性关系。我们这里学习的是线性回归,它有一个非常重要的假设,它要假设数据间真的存在一定的线性关系,这里说的线性关系可以是正相关的线性关系,也可以是负相关的线性关系,只是那个斜率是大于0还是小于0而已。但是如果你的数据完全没有线性关系的话,那很有可能得到的 R方是小于0的,那么此时你可能就要考虑一下不能使用线性回归法来解决这个问题了。

  那么最后,在具体实现的层面上,我们再来仔细看一下 R方这个式子,是不是这个式子有点眼熟,如果我们将 1 减去的那部分式子分子分母同时除以 m ,分子计算的就是 MSE,分母计算的就是方差。
在这里插入图片描述
在这里插入图片描述
  如果我们将 R方写成了式子(3) 这种形式,计算R方也会变得非常容易。那么通过这个式子,可能会隐约的感到R方背后还有更加深刻的统计意义,由于我是初学,我就不深究了,有兴趣的小伙伴可以自行查阅相关资料。


编程实现

  下面我就来编程实现 R Square 这个十分重要的标准。

  我们接着上一篇博客的 Jupyter Notebook 接着编写代码。

在这里插入图片描述
  下面我们将该方法(r2_score)封装我们自己编写的 metrics.py 文件中。

import numpy as np
from math import sqrt

def accuracy_score(y_true, y_predict):
    """计算y_true和y_predict之间的准确率"""
    assert y_true.shape[0] == y_predict.shape[0], \
        "the size of y_true must be equal to the size of y_predict"
    return sum(y_true == y_predict) / len(y_true)

# MSE:均方误差
def mean_squared_error(y_true, y_predict):
    """计算y_true与y_predict之阿的MSE"""
    assert len(y_true) == len(y_predict), \
        "the size of y_true must be equal to the size of y_predict"
    return np.sum((y_true - y_predict) ** 2) / len(y_true)

# RMSE:均方根误差
def root_mean_squared_error(y_true, y_predict):
    """计算y_true与y_predict之阿的RMSE"""
    return sqrt(mean_squared_error(y_true, y_predict))

# MAE:平均绝对误差
def mean_absolute_error(y_true, y_predict):
    """计算y_true与y_predict之阿的MAE"""
    assert len(y_true) == len(y_predict), \
        "the size of y_true must be equal to the size of y_predict"
    return np.sum(np.absolute(y_true - y_predict)) / len(y_true)

# R Square
def r2_score(y_true, y_predict):
    """计算y_true和y_predict之间的R Square"""
    return 1 - mean_squared_error(y_true, y_predict) / np.var(y_true)

在这里插入图片描述
在这里插入图片描述

  最后一点,非常值得一提的是,在 sklearn 中线性回归算法被封装在了 LinearRegression 中,只不过这个 LinearRegression 直接就支持了多元线性回归,由于我现在还只是在学习简单的线性回归,所以现在暂时先不使用这个类。

  我们回忆一下,之前我们学习的 kNN 算法,在 kNN 算法里会直接封装一个 score 这样的函数直接来度量算法本身的准确度。那么对于回归算法也一样,它里面相应的也有一个 score 的函数。
在这里插入图片描述
  我们可以看到这个 score 函数直接返回R方这个标准。从这里我们也可以看出来,R方这个标准实在太重要了,也是使用最为广泛的一种标准。那么,我们在我们自己写的 SimpleLinearRegression 中也增加一个 score 函数。

# SimpleLinearRegression.py

import numpy as np
from metrics import r2_score
# 使用向量化运算
class SimpleLinearRegression:
    def __init__(self):
        """初始化 Simple Linear Regression 模型"""
        self.a_ = None
        self.b_ = None
    def fit(self, x_train, y_train):
        """根据训练数据集 x_train, y_train训练模型"""
        assert x_train.ndim == 1, \
            "Simple Linear Regression can only solve single feature training data"
        assert len(x_train) == len(y_train), \
            "the size of x_train must be equal to the size of y_train"

        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)

        num = (x_train - x_mean).dot(y_train - y_mean) #分子点乘
        d = (x_train - x_mean).dot(x_train - x_mean) #分母点乘

        self.a_ = num / d
        self.b_ = y_mean - self.a_ * x_mean

        return self
    def predict(self, x_predict): # x_predict 为一个向量
        """给定预测数据集x_predict, 返回表示x_predict的结果向量"""
        assert x_predict.ndim == 1, \
            "Simple Linear Regression can only solve single feature training data"
        assert self.a_ is not None and self.b_ is not None, \
            "must fit before predict!"
        return np.array([self._predict(x) for x in x_predict])
    def _predict(self, x_single): # x_single 为一个数
        """给定单个预测数据x_single, 返回x_single的预测结果值"""
        return self.a_ * x_single + self.b_
    def score(self, x_test, y_test):
        """根据测试数据集x_test和y_test确定当前模型的准确度"""
        y_predict = self.predict(x_test)
        return r2_score(y_test, y_predict)
    def __repr__(self):
        return "SimpleLinearRegression()"

在这里插入图片描述

  到此,我们简单线性回归的学习就到此为止了,其实对于算法部分,还是比较简单的,对于怎么使用算法?怎么评价算法?对于这些问题,可能有很多值得深究的地方。

  后面,我将会抛弃掉简单线性回归中每一个样本只能有一个特征这个条件。对于每一个样本,可以有多个特征,n 个特征这样的更加一般的形式,相应的就是多元线性回归问题。


具体代码见 14 回归算法的评价.ipynb

猜你喜欢

转载自blog.csdn.net/qq_41033011/article/details/109012402