大数据,机器学习,人工智能人工智能/模式识别/机器学习精华专题机器学习与数据挖掘

机器学习系列(十二)——衡量回归算法性能的标准

2019-07-07  本文已影响28人  Ice_spring

MSE,RMSE,MAE

(Mean Square Error,Root ~,Mean Absolute Error)
在分类算法中,我们用准确率作为评价模型好坏的标准。在回归问题中,由于是拟合,自然没有准确率这样的说法,以简单线性回归为例,下面介绍常用的回归衡量指标。
在简单线性回归中,我们的目标是找到a和b,使得
{\sum_{i=1}^m(y_{train}^{(i)}-ax_{train}^{(i)}-b)^{2}}

尽可能小。
为了测试模型性能,需要看模型在测试集上的预测与真实值的误差:
{\sum_{i=1}^m(y_{test}^{(i)}-\widehat{y}_{test}^{(i)})^{2}}

不过这个表达式与m有关,假如现在有两个模型,一个m为1000误差为100,而另一个m为100误差90,显然前一个模型更好,于是为了消除测试个数对模型评价的影响,改进上式得到均方误差MSE
\frac{1}{m}{\sum_{i=1}^m(y_{test}^{(i)}-\widehat{y}_{test}^{(i)})^{2}}

当然这种方式虽然衡量误差没问题,但是量纲上却不对应,不具有好的可解释性,于是再对上式开方得到改进的均方根误差RMSE
\sqrt{\frac{1}{m}{\sum_{i=1}^m(y_{test}^{(i)}-\widehat{y}_{test}^{(i)})^{2}}}

另外有平均绝对误差MAE
\frac{1}{m}{\sum_{i=1}^m|y_{test}^{(i)}-\widehat{y}_{test}^{(i)}|}

这个在衡量误差上同样很好,量纲也对应,但是它并非处处可导,不方便求极值和分析。


实现衡量标准

使用boston房产数剧集,该数剧集共506个样本,13个特征,为了可视化和算法介绍的方便,取其中一个特征做分析。

from sklearn import datasets
boston = datasets.load_boston()
x = boston.data[:,5]
'''只使用房间数量(rm)特征,rm是第六个特征'''
y = boston.target
boston1

首先绘制大致的散点图,可以发现图中最上的数据似乎有些异常,实际上是现实中可能有一些超过范围的点都被记录为边界点。

'''考虑到现实中可能有一些超过范围的点都被记录为边界,所以删除它们'''
x = x[y < 50.0]
y = y[y < 50.0]
plt.scatter(x,y)
plt.show()
boston2

接下来调用play_Ml中的线性回归:

from play_Ml.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,seed=666)
from play_Ml.SimpleLinearRegression import SimpleLinearRegression2
reg = SimpleLinearRegression2()
reg.fit(x_train,y_train)
model

为了衡量模型性能好坏,自己实现评价指标,在metrics.py中添加评价指标:

import numpy as np
from math import sqrt

def accuracy_score(y_true,y_predict):
    assert y_true.shape[0] == y_predict.shape[0],"must be the same"
    return sum(y_true == y_predict)/len(y_true)

def mean_square_error(y_true,y_predict):
    assert len(y_true) == len(y_predict),"must be the same!"

    return np.sum((y_predict-y_true)**2)/len(y_true)

def root_mean_square_error(y_true,y_predict):
    return sqrt(mean_square_error(y_true,y_predict))

def mean_absolute_error(y_true,y_predict):
    return np.sum(np.absolute(y_predict - y_true))/len(y_true)

使用评价指标:

from play_Ml.metrics import mean_absolute_error
from play_Ml.metrics import mean_square_error
from play_Ml.metrics import root_mean_square_error
mean_absolute_error(y_test,y_predict)
root_mean_square_error(y_test,y_predict)
mean_square_error(y_test,y_predict)
evaluate

当然也可以直接使用sklearn中封装好的,效果是一样的:

from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error
mean_square_error(y_test,y_predict)

不过sklearn中没有rmse指标,可以求得mse再自行开根。


最好的回归衡量指标R Squared

对于分类问题,我们可以通过模型在不同问题上的准确率去判断一个模型的好坏,但是对于回归问题不能这样,比如MSE在考试成绩预测时为10,在房价预测时为5,但显然不能说在房价预测上表现更好。
这个问题有解决的办法,那就是R Squared指标。
R^{2}=1-\frac{SS_{residual}}{SS_{total}}

其中SS_{residual}是残差平方和,SS_{total}是朴素模型(基准模型)差距平方和,它们分别可看作是使用我们的模型预测产生的错误和使用均值预测产生的错误。
R^{2}=1-\frac{\sum_{i}(\widehat{y}^{(i)}-y^{(i)})^{2}}{\sum_{i}(\overline{y}^{(i)}-y^{(i)})^{2}}=1-\frac{MSE}{Var}

因为SS_{total}是想象的与x无关的一个模型(baseline model),它是一个很朴素的预测。因此可以这样理解R squared,我们的模型预测会产生错误,baseline model预测也会产生错误而且比较大。这样表达式的含义就是我们的模型对比基准模型拟合通过的数据程度。它的取值范围是0-1,比如R^{2}=1时,表示我们的模型表现完美,没有任何误差。R^{2}=0时,表示我们的模型和baseline model表现一样。
R^{2}将回归结果的好坏也归到0-1之间,这是很方便分析的。
在metrics.py中加入R方指标:

def r2_score(y_true,y_predict):
    return 1 - mean_square_error(y_true,y_predict)/np.var(y_true)

使用我们的R方指标:

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

调用sklearn使用R方指标:

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

实际在sklearn线性回归score函数中封装的直接是R方指标,可见R方指标是很重要的。
最后将score加入SimpleLinearRegression.py:

import numpy as np
from .metrics import r2_score 
class SimpleLinearRegression:
    def __init__(self):
        '''初始化简单线性回归模型'''
        self.a_ = None
        self.b_ = None
        
    def fit(self,x_train,y_train):
        '''训练模型'''
        assert x_train.ndim == 1,"one feature!"
        assert len(x_train) == len(y_train),"size must be the same!"
        
        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,返回结果向量'''
        assert x_predict.ndim == 1,"one feature!"
        assert self.a_ is not None and self.b_ is not None,"fit first!"
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self,x_single):
        '''给定单个待预测数据,返回预测结果'''
        return self.a_*x_single+self.b_

    def score(self,x_test,y_test):
        y_predict = self.predict(x_test)
        return r2_score(y_test,y_predict)

    def __repr__(self):
        return "SimpleLinearRegression()"

使用方式和调用sklearn中的类似:

from play_Ml.SimpleLinearRegression import SimpleLinearRegression
reg = SimpleLinearRegression()
reg.fit(x_train,y_train)
reg.score(x_test,y_test)
上一篇下一篇

猜你喜欢

热点阅读