美文网首页
06 模型之母:线性回归的评价指标

06 模型之母:线性回归的评价指标

作者: Japson | 来源:发表于2019-12-15 00:40 被阅读0次

    本文为饼干Japson原创,首发于公众号《数据科学家联盟》。更多大数据、机器学习、深度学习相关内容,敬请关注公众号。

    0 前言:

    本篇内容是线性回归系列的第三篇。

    在《模型之母:简单线性回归&最小二乘法》、《模型之母:简单线性回归&最小二乘法》中我们学习了简单线性回归、最小二乘法,并完成了代码的实现。在结尾,我们抛出了一个问题:在之前的kNN算法(分类问题)中,使用分类准确度来评价算法的好坏,那么回归问题中如何评价好坏呢?

    本篇内容就是关于回归模型的评价,首先介绍线性回归模型的三个常用评价方法,然后通过波士顿房产预测的实际例子,对评价方法进行代码实现。最后我们会隆重引出最好的衡量线性回归法的指标:R Square

    1 线性回归算法的衡量标准

    简单线性回归的目标是:

    已知训练数据样本xy ,找到ab的值,使 \sum_{i=1}^{m} (y^{(i)}-ax^{i}-b)^{2} 尽可能小

    实际上是找到训练数据集中 \sum (y_{train}^{(i)} - \hat{y}\_{train}^{(i)})^2 最小。

    衡量标准是看在测试数据集中y的真实值与预测值之间的差距。

    因此我们可以使用下面公式作为衡量标准:
    \sum (y_{train}^{(i)} - \hat{y}\_{train}^{(i)})^2

    但是这里有一个问题,这个衡量标准是和m相关的。在具体衡量时,测试数据集不同将会导致误差的累积量不同。因此很快的

    首先我们从“使损失函数尽量小”这个思路出发:

    对于训练数据集合来说,使 \sum_{i=1}^{m} (y^{(i)}_{train} - ax^{i}_{train}-b)^{2} 尽可能小

    在得到a和b之后将 x_{test} 代入a、b中。可以使用 \sum_{i=1}^{m} (y_{test}^{(i)}-\hat y_{test}^{(i)})^2 来作为衡量回归算法好坏的标准。

    1.1 均方误差MSE

    测试集中的数据量m不同,因为有累加操作,所以随着数据的增加 ,误差会逐渐积累;因此衡量标准和 m 相关。为了抵消掉数据量的形象,可以除去数据量,抵消误差。通过这种处理方式得到的结果叫做 均方误差MSE(Mean Squared Error)
    \frac 1 m \sum_{i=1}^{m} (y_{test}^{(i)}-\hat y_{test}^{(i)})^2

    1.2 均方根误差RMSE

    但是使用均方误差MSE收到量纲的影响。例如在衡量房产时,y的单位是(万元),那么衡量标准得到的结果是(万元平方)。为了解决量纲的问题,可以将其开方(为了解决方差的量纲问题,将其开方得到平方差)得到均方根误差RMSE(Root Mean Squarde Error)
    \sqrt{\frac 1 m \sum_{i=1}^{m} (y_{test}^{(i)}-\hat y_{test}^{(i)})^2} = \sqrt {MSE_{test}}

    1.3 平均绝对误差MAE

    对于线性回归算法还有另外一种非常朴素评测标准。要求真实值 y_{test}^{(i)}) 与 预测结果 \hat y_{test}^{(i)}) 之间的距离最小,可以直接相减做绝对值,加m次再除以m,即可求出平均距离,被称作平均绝对误差MAE(Mean Absolute Error)
    \frac 1 m \sum_{i=1}^{m} |y_{test}^{(i)}-\hat y_{test}^{(i)}|
    在之前确定损失函数时,我们提过,绝对值函数不是处处可导的,因此没有使用绝对值。但是在评价模型时不影响。因此模型的评价方法可以和损失函数不同。

    2 评价标准的代码实现

    2.1 数据探索

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn import datasets
    
    # 查看数据集描述
    boston = datasets.load_boston()
    print(boston.DESCR)
    

    (输出略)

    因为是测试简单回归算法,因此我们选择其中的一个特征进行建模。 选择:

    • RM average number of rooms per dwelling 每个住宅的平均房间数

    下面我们进行简单的数据探索:

    # 查看数据集的特征列表
    boston.feature_names
    输出:
    array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
           'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')
           
    # 取出数据中的第六例的所有行(房间数量)
    x = boston.data[:,5]
    x.shape
    输出:
    (506,)
    
    # 取出样本标签
    y = boston.target
    y.shape
    输出:
    (506,)
    
    plt.scatter(x,y)
    plt.show()
    
    15725961211188.jpg

    在图中我们可以看到 50W 美元的档分布着一些点。这些点可能是超出了限定范围(比如在问卷调查中,价格的最高档位是“50万及以上”,那么就全都划到50W上了,因此在本例中,可以将这部分数据去除)

    np.max(y)
    # 这里有一个骚操作,用比较运算符返回一个布尔值的向量,将其作为索引,直接在矩阵里对每个元素进行过滤。
    x = x[y < 50.0]
    y = y[y < 50.0]
    plt.scatter(x,y)
    plt.show()
    
    15725961519489.jpg

    2.2 简单线性回归预测

    from myAlgorithm.model_selection import train_test_split
    
    x_train, x_test, y_train, y_test = train_test_split(x, y, seed=666)
    print(x_train.shape)    # (392,)
    print(y_train.shape)    #(392,)
    print(x_test.shape)     #(98,)
    print(y_test.shape)     #(98,)
    
    from myAlgorithm.SimpleLinearRegression import SimpleLinearRegression
    
    reg = SimpleLinearRegression()
    reg.fit(x_train,y_train)
    print(reg.a_)   # 7.8608543562689555
    print(reg.b_)   # -27.459342806705543
    
    plt.scatter(x_train,y_train)
    plt.plot(x_train, reg.predict(x_train),color='r')
    plt.show()
    
    15725961674285.jpg
    y_predict = reg.predict(x_test)
    print(y_predict)
    

    (输出略)

    2.3 MSE 均方误差

    mse_test = np.sum((y_predict - y_test) ** 2) / len(y_test)
    mse_test
    

    24.156602134387438

    2.4 RMSE 均方根误差

    from math import sqrt
    
    rmse_test = sqrt(mse_test)
    rmse_test
    

    4.914936635846635

    RMSE消除了量纲的差异,输出的结果是4.9,与y的量纲相同。解释为在RMSE指标下,我们预测的房产数据平均误差在4.9万美元左右。

    2.5 MAE 平均绝对误差

    mae_test = np.sum(np.absolute(y_predict - y_test)) / len(y_test)
    mae_test
    

    3.5430974409463873

    在MAE指标下,我们预测的房产数据平均误差在3.54万美元左右。我们看到MAE指标得到的误差要比RMSE指标得到的误差小。说明不同的评价指标的结果不同

    从数学角度来分析,RMSE和MAE的量纲相同,但RMSE的结果较大,这是因为RMSE是将错误值平方,平方操作会放大样本中预测结果和真实结果较大的差距。MAE没有放大。而我们就是要解决目标函数最大差距,因为选RMSE更好一点

    3 封装及调用

    3.1 在工程文件中封装

    在工程文件的metrics.py中添加以上评价指标:

    mport 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)
    
    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)
    
    def root_mean_squared_error(y_true, y_predict):
        """计算y_true和y_predict之间的RMSE"""
        return sqrt(mean_squared_error(y_true, y_predict))
    
    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_predict - y_true)) / len(y_predict)
    

    3.2 调用

    我们可以在jupyter notebook进行调用:

    from myAlgorithm.metrics import mean_squared_error
    from myAlgorithm.metrics import root_mean_squared_error
    from myAlgorithm.metrics import mean_absolute_error
    
    mean_squared_error(y_test, y_predict)
    # 输出:24.156602134387438
    
    root_mean_squared_error(y_test, y_predict)
    # 输出:4.914936635846635
    
    mean_absolute_error(y_test, y_predict)
    # 输出:3.5430974409463873
    

    3.3 sklearn中的MSE和MAE

    sklearn中不存在RMSE,我们可以手动对MSE开方:

    from sklearn.metrics import mean_squared_error
    from sklearn.metrics import mean_absolute_error
    
    mean_squared_error(y_test, y_predict)
    # 输出:24.156602134387438
    
    mean_absolute_error(y_test, y_predict)
    # 输出:3.5430974409463873
    

    其实我们

    4 更好用的 R Square

    4.2 R Square介绍以及为什么好

    分类准确率,就是在01之间取值。但RMSE和MAE没有这样的性质,得到的误差。因此RMSE和MAE就有这样的局限性,比如我们在预测波士顿方差,RMSE值是4.9(万美元) 我们再去预测身高,可能得到的误差是10(厘米),我们不能说后者比前者更准确,因为二者的量纲根本就不是一类东西。

    其实这种局限性,可以被解决。用一个新的指标R Squared。

    R^{2} = 1 - \frac {SS_{residual}} {SS_{total}} = 1 - \frac {\sum{ (\hat{y}^{(i)} - y^{(i)})^2 }} {\sum{ (\bar{y} - y^{(i)})^2 }}

    R方这个指标为什么好呢?

    • 对于分子来说,预测值和真实值之差的平方和,即使用我们的模型预测产生的错误。
    • 对于分母来说,是均值和真实值之差的平方和,即认为“预测值=样本均值”这个模型(Baseline Model)所产生的错误。
    • 我们使用Baseline模型产生的错误较多,我们使用自己的模型错误较少。因此用1减去较少的错误除以较多的错误,实际上是衡量了我们的模型拟合住数据的地方,即没有产生错误的相应指标

    我们根据上述分析,可以得到如下结论:

    • R^2 <= 1
    • R2越大也好,越大说明减数的分子小,错误率低;当我们预测模型不犯任何错误时,R2最大值1
    • 当我们的模型等于基准模型时,R^2 = 0
    • 如果R^2 < 0,说明我们学习到的模型还不如基准模型。此时,很有可能我们的数据不存在任何线性关系。

    4.2 R Square实现

    下面我们从具体实现的层面再来分析一下R方:

    R^{2} = 1 - \frac {\sum{ (\hat{y}^{(i)} - y^{(i)})^2 / m }} {\sum{ (\bar{y} - y^{(i)})^2 / m }}

    如果分子分母同时除以m,我们会发现,分子就是之前介绍过的均方误差,分母实际上是y这组数据对应的方差:

    R^{2} = 1 - \frac {MSE(\hat{y}^{(i)},y)} {Var(y)}

    下面我们具体编程实践一下:

    1 - mean_squared_error(y_test, y_predict) / np.var(y_test)
    

    输出:
    0.61293168039373225

    下面我们在工程文件metrics.py中添加自己实现的r2_score方法:

    def score(self, x_test, y_test):
        """根据测试数据x_test、y_test计算简单线性回归准确度(R方)"""
        y_predict = self.predict(x_test)
        return r2_score(y_test, y_predict)
    

    然后我们再来调用它:

    from myAlgorithm.metrics import r2_score
    r2_score(y_test, y_predict)
    

    其实这跟掉sklearn中的方法相同:

    from sklearn.metrics import r2_score
    r2_score(y_test, y_predict)
    

    5 总结

    线性回归的评价指标与分类的评价指标有很大的不同,本篇介绍了均方误差MSE(预测值与真实值之差的平方和,再除以样本量)、均方根误差RMSE(为了消除量纲,将MSE开方)、平均绝对误差MAE(预测值与真实值之差的绝对值,再除以样本量)、以及非常重要的、效果非常好的R方(因此用1减去较少的错误除以较多的错误,实际上是衡量了我们的模型拟合住数据的地方,即没有产生错误的相应指标)。

    在实际应用过程中,我们需要这些评价指标,来判别模型的好坏。

    在下一篇,我们将会抛弃简单线性回归中每个样本只能有一个特征的限制,考虑更一般的、多个特征的多元线性回归。


    公众号二维码.jpeg

    相关文章

      网友评论

          本文标题:06 模型之母:线性回归的评价指标

          本文链接:https://www.haomeiwen.com/subject/gzfknctx.html