机器学习系列(十一)——线性回归Linear Regressio

作者: Ice_spring | 来源:发表于2019-07-07 10:33 被阅读7次

    线性回归算法

    和knn算法不同,线性回归算法主要用于解决回归问题,它同样思想简单,实现容易,而且是许多强大的非线性模型(如SVM)的基础。
    线性回归的结果具有很好的可解释性,蕴含机器学习中很多重要的思想。因此线性回归也是非常重要的机器学习算法。
    以一个房价预测为例,来说明什么是线性回归:

    housePrice

    在该例子中,线性回归算法认为房价和房屋面积存在一定的线性关系,于是为了更好地描述模型,需要寻找一条直线,这条直线能最大程度拟合样本特征和样本输出标记之间的关系。在本例子中只有一个特征即房屋面积,输出标记为价格。如果有两个特征则需要在三维坐标系中画图,如果有更多特征则需要更高维度空间。为了可视化方便,本文将都以一个特征为例进行讲解。
    对于样本特征只有一个的线性回归,我们称之为简单线性回归,对于多个特征的线性回归可以由简单线性回归进行推广。
    在房价的例子中,如果我们找到了这条拟合直线y=ax+b,那么之后如果知道了房屋面积就可以进行房价的预测。
    \widehat{y}^{(i)}=ax^{(i)}+b

    hp_regression

    于是,我们希望真实的y^{(i)}\widehat{y}^{(i)}的差距尽量小,考虑所有的样本,他们的差距表示为:
    \sum_{i=1}^m(y^{(i)}-\widehat{y}^{(i)})^{2}

    \widehat{y}^{(i)}带入,我们的目标就是想办法找到参数ab让差距尽可能小。这个差距称之为损失函数(loss function)。
    这也是机器学习算法的基本思路,模型要尽可能拟合数据,使输出与真实数据差距最小。有时会使用评价拟合程度的函数,称之为效用函数(utility function),这个则要越大越好。不管如何,都是通过分析问题确定问题的损失函数或者效用函数,通过最优化损失函数或者效用函数,获得机器学习的模型。近乎所有参数学习算法都是这样的套路。区别就在于要优化的目标函数不同(线性回归,多项式回归,SVM,NN...)。有一门与机器学习相关的《最优化原理》(运筹学)课程就是探讨最优理论的,有兴趣的可以查阅学习一下。
    回到上面的线性回归问题,这是一个典型的最小二乘法问题,最小化误差的平方。在数学上可以用Lagrange乘数法很简单地求得最优的a和b,这里直接给出他们的表达式:
    a=\frac{\sum_{i=1}^m(x^{(i)}-\overline{x})(y^{(i)}-\overline{y})}{\sum_{i=1}^m(x^{(i)}-\overline{x})^{2}}

    b=\overline{y}-a\overline{x}

    实现Simple Linear Regression

    使用模拟数剧集来实现线性回归。

    import numpy as np
    import matplotlib.pylab as plt
    x=np.array([1,2,3,4,5],dtype=float)
    y=np.array([1,3,2,3,5],dtype=float)
    plt.scatter(x,y)
    plt.axis([0,6,0,6])
    plt.show()
    
    模拟数据
    '''计算a和b'''
    x_mean = np.mean(x)
    y_mean = np.mean(y)
    num = 0.0
    d = 0.0
    for x_i,y_i in zip(x,y):
        num += (x_i-x_mean)*(y_i-y_mean)
        d += (x_i-x_mean)**2
    a = num/d
    b = y_mean - a*x_mean
    '''画出线性回归拟合直线'''
    plt.scatter(x,y)
    plt.plot(x,y_hat,color='r')
    plt.axis([0,6,0,6])
    plt.show()
    
    拟合直线 a和b

    下面进行类似sklearn的算法封装,在play_Ml中新建SimpleLinearRegression.py,代码如下:

    import numpy as np
    
    class SimpleLinearRegression1:
        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 = 0.0
            d = 0.0
            for x_i,y_i in zip(x_train,y_train):
                num += (x_i-x_mean)*(y_i-y_mean)
                d += (x_i-x_mean)**2
            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 __repr__(self):
            return "SimpleLinearRegression1()"
    

    使用我们的算法:


    ownLog

    可以发现得到的和上面是一样的结果。

    向量化运算提升算法性能

    上面计算a和b时,使用for循环是最基本的复合逻辑的算法,不过考虑到numpy模块可以进行向量化运算加快运算速度,可以做如下修改:

    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
    

    只需要修改其中的fit函数即可,测试发现,进行向量化运算可以带来10倍以上的性能提升。

    相关文章

      网友评论

        本文标题:机器学习系列(十一)——线性回归Linear Regressio

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