线性回归算法

本文参考公共号《数据科学家联盟》饼干文章。

 

一、简单线性回归:简单线性回归及最小二乘法的数据推导

        所谓简单,是指只有一个样本特征,即只有一个自变量;所谓线性,是指方程是线性的;所谓回归,是指用方程来模拟变量之间是如何关联的。 简单线性回归,其思想简单,实现容易(与其背后强大的数学性质相关。同时也是许多强大的非线性模型(多项式回归、逻辑回归、SVM)的基础。并且其结果具有很好的可解释性。

1、推导思路:

找到一组参数,使得真实值与预测值之间的差距尽可能地小,是一种典型的机器学习算法的推导思路

我们所谓的建模过程,其实就是找到一个模型,最大程度的拟合我们的数据。 在简单线回归问题中,模型就是我们的直线方程:y = ax + b 。 要想最大的拟合数据,本质上就是找到没有拟合的部分,也就是损失的部分尽量小,就是损失函数(loss function)(也有算法是衡量拟合的程度,称函数为效用函数(utility function))_auto_0

因此,推导思路为: 1.通过分析问题,确定问题的损失函数或者效用函数; 2.然后通过最优化损失函数或者效用函数,获得机器学习的模型 近乎所有参数学习算法都是这样的套路,区别是模型不同,建立的目标函数不同,优化的方式也不同。 回到简单线性回归问题,目标:

已知训练数据样本X、y ,找到a和b的值,使_auto_1尽可能小

这是一个典型的最小二乘法问题(最小化误差的平方) 通过最小二乘法可以求出a、b的表达式:_auto_2

2、最小二乘法

2.1 损失函数

在机器学习中,所有的算法模型其实都依赖于最小化或最大化某一个函数,我们称之为“目标函数”。 最小化的这组函数被称为“损失函数”。什么是损失函数呢?

损失函数描述了单个样本预测值和真实值之间误差的程度。用来度量模型一次预测的好坏。

 

损失函数是衡量预测模型预测期望结果表现的指标。损失函数越小,模型的鲁棒性越好。。 常用损失函数有:

  • 0-1损失函数:用来表述分类问题,当预测分类错误时,损失函数值为1,正确为0_auto_0

  • 平方损失函数:用来描述回归问题,用来表示连续性变量,为预测值与真实值差值的平方。(误差值越大、惩罚力度越强,也就是对差值敏感)_auto_1

  • 绝对损失函数:用在回归模型,用距离的绝对值来衡量_auto_2

  • 对数损失函数:是预测值Y和条件概率之间的衡量。事实上,该损失函数用到了极大似然估计的思想。P(Y|X)通俗的解释就是:在当前模型的基础上,对于样本X,其预测值为Y,也就是预测正确的概率。由于概率之间的同时满足需要使用乘法,为了将其转化为加法,我们将其取对数。最后由于是损失函数,所以预测正确的概率越高,其损失值应该是越小,因此再加个负号取个反。_auto_3

以上损失函数是针对于单个样本的,但是一个训练数据集中存在N个样本,N个样本给出N个损失,如何进行选择呢? 这就引出了风险函数。

2.2 期望风险

期望风险是损失函数的期望,用来表达理论上模型f(X)关于联合分布P(X,Y)的平均意义下的损失。又叫期望损失/风险函数。_auto_0

2.3 经验风险

模型f(X)关于训练数据集的平均损失,称为经验风险或经验损失。 其公式含义为:模型关于训练集的平均损失(每个样本的损失加起来,然后平均一下)_auto_1

经验风险最小的模型为最优模型。在训练集上最小经验风险最小,也就意味着预测值和真实值尽可能接近,模型的效果越好。公式含义为取训练样本集中对数损失函数平均值的最小。_auto_2

2.4 经验风险最小化和结构风险最小化

期望风险是模型关于联合分布的期望损失,经验风险是模型关于训练样本数据集的平均损失。根据大数定律,当样本容量N趋于无穷时,经验风险趋于期望风险。 因此很自然地想到用经验风险去估计期望风险。但是由于训练样本个数有限,可能会出现过度拟合的问题,即决策函数对于训练集几乎全部拟合,但是对于测试集拟合效果过差。因此需要对其进行矫正:

  • 结构风险最小化:当样本容量不大的时候,经验风险最小化容易产生“过拟合”的问题,为了“减缓”过拟合问题,提出了结构风险最小理论。结构风险最小化为经验风险与复杂度同时较小。_auto_3

通过公式可以看出,结构风险:在经验风险上加上一个正则化项(regularizer),或者叫做罚项(penalty) 。正则化项是J(f)是函数的复杂度再乘一个权重系数(用以权衡经验风险和复杂度)

2.5最小二乘法

 

_auto_0

那么为了求出这个二次函数的最小值,对其进行求导,导数为0的时候取得最小值:_auto_1

进而:_auto_2

正好是算数平均数(算数平均数是最小二乘法的特例)。 这就是最小二乘法,所谓“二乘”就是平方的意思。 (高斯证明过:如果误差的分布是正态分布,那么最小二乘法得到的就是最有可能的值。)

 

二、简单线性回归实现及向量化应用

python手动实现

import numpy as np

class SimpleLinearRegression:
    def __init__(self):
        """模型初始化函数"""
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """根据训练数据集x_train,y_train训练模型"""
        assert x_train.ndim ==1
        '''简单线性回归模型仅能够处理一维特征向量'''
        assert len(x_train) == len(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的结果向量"""
        assert x_predict.ndim == 1
        '''简单线性回归模型仅能够处理一维特征向量'''
        assert self.a_ is not None and self.b_ is not None
        '''先训练之后才能预测'''
        return np.array([self._predict(x) for x in x_predict])

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

    def __repr__(self):
        """返回一个可以用来表示对象的可打印字符串"""
        return "SimpleLinearRegression()"

向量化运算:

向量w和向量v,每个向量的对应项,相乘再相加。其实这就是两个向量“点乘”

这样我们就可以使用numpy中的dot运算,非常快速地进行向量化运算。

总的来说:向量化是非常常用的加速计算的方式,特别适合深度学习等需要训练大数据的领域。

对于 y = wx + b, 若 w, x都是向量,那么,可以用两种方式来计算,第一是for循环:

y = 0
for i in range(n):
    y += w[i]*x[i]
    y += b

向量化

y = np.dot(w,x) + b

对于独立的样本,用for循环串行计算的效率远远低于向量化后,用矩阵方式并行计算的效率。因此: 只要有其他可能,就不要使用显示for循环。

三、多元线性回归:多选线性回归和正规方程解及实现

1.通过分析问题,确定问题的损失函数或者效用函数;

2.然后通过最优化损失函数或者效用函数,获得机器学习的模型。然后我们推导并实现了最小二乘法,然后实现了简单线性回归。最后还以简单线性回归为例,学习了线性回归的评价指标:均方误差MSE、均方根误差RMSE、平均绝对MAE以及R方。

但是,在真实世界中,一个样本通常有很多(甚至成千上万)特征值的,这就是多元线性回归。本篇内容我们学习多元线性回归并实现。

 

对于下面的样本数据集_auto_0

对应的是一个向量,每一行是一个样本,每列对应一个特征。对应的结果可以用如下如下公式:_auto_1

简单线性回归,只计算前两项,但是在多元线性回归中就要学习到n+1个参数,就能求出多元线性回归预测值:_auto_2

也就是:第一个特征与参数1相乘、第二个特征与参数2相乘,累加之后再加上截距。就能得到预测值。 求解思路也与简单线性回归非常一致,目标同样是:

已知训练数据样本X、y ,找到_auto_3

,使_auto_4

尽可能小.

 

其中_auto_0

是列向量列向量,而且我们注意到,可以虚构第0个特征X0,另其恒等于1,推导时结构更整齐,也更加方便:_auto_1

这样我们就可以改写成向量点乘的形式:_auto_2

此时,我们可以得出:_auto_3

因此我们可以把目标写成向量化的形式:

已知训练数据样本X、y ,_auto_4

推导出可以得到多元线性回归的正规方程解_auto_5

当然了,具体的推导过程不需要了解的,不影响我们的使用,我们只要知道结果思想就行,结果也不用背下来,在网上搜一下就能找到。

但是这种朴素的计算方法,缺点是时间复杂度较高:O(n^3),在特征比较多的时候,计算量很大。优点是不需要对数据进行归一化处理,原始数据进行计算参数,不存在量纲的问题(多选线性没必要做归一化处理)。

python代码实现多元线性回归:

import numpy as np
from sklearn.metrics import r2_score

class LinearRegression:

    def __init__(self):
        """初始化Linear Regression模型"""
        self.coef_ = None    # 系数(theta0~1 向量)
        self.interception_ = None   # 截距(theta0 数)
        self._theta = None  # 整体计算出的向量theta

    def fit_normal(self, X_train, y_train):
        """根据训练数据X_train,y_train训练Linear Regression模型"""
        assert X_train.shape[0] == y_train.shape[0]
        '''the size of X_train must be equal to the size of y_train'''
        # 正规化方程求解
        X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
        self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)

        self.interception_ = self._theta[0]
        self.coef_ = self._theta[1:]
        return self

    def predict(self, X_predict):
        """给定待预测的数据集X_predict,返回表示X_predict的结果向量"""
        assert self.interception_ is not None and self.coef_ is not None
        '''must fit before predict'''
        assert X_predict.shape[1] == len(self.coef_)
        '''the feature number of X_predict must be equal to X_train'''
        X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
        y_predict = X_b.dot(self._theta)
        return y_predict

    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 "LinearRegression()"

 

posted @ 2019-11-30 22:09  yancheng111  阅读(548)  评论(0编辑  收藏  举报