大数据,机器学习,人工智能学-机器学习机器学习和人工智能入门

3 线性回归算法

2019-05-26  本文已影响5人  壮少Bryant

线性回归分为:

1 简单线性回归

寻找一条直线,最大程度的拟合样本特征与样本输出标记之间的关系。

分类与回归之间的直观性区分

预测值为:\hat{y}^{(i)} = ax^{(i)} + b ,真值为y^{(i)}

我们希望y^{(i)}-\hat{y}^{(i)}的差距尽量小

考虑所有样本:找到a和b,使\sum_1^m(y^{(i)}-\hat{y}^{(i)})^2 = \sum_1^m(y^{(i)}-ax^{(i)} - b)^2 尽可能小

损失函数定义:用来度量预测错误的程度。
近乎所有参数学习算法,都是通过分析问题,确定问题的损失函数,通过最优化损失函数,使得预测错误的程度最小,来获得机器学习的模型。

1.1 最小二乘法

求a,b的过程,就是对a,b分别求导,令极值为0,求方程组的过程。

先给出结论:
b = \overline{y} - a\overline{x}
a = \sum_1^m\frac{(x^{(i)}-\overline{x})(y^{(i)}-\overline{y}) }{(x^{(i)}-\overline{x})^2}
公式编辑太麻烦,还是直接上图看推导过程吧,


此时求得 b = \overline{y} - a\overline{x},将其带入到对a求导中


此时根据红框里的等式进行变换,最终得到下面的式子

那么化简成这样的意义是什么呢?有什么好处呢?

答:向量化运算
使用for循环的效率是很低的,用向量的运算,效率会大大提高(相差好几十倍)。

1.2 代码起飞

import numpy as np

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训练Simple Linear Regression模型"""
        assert x_train.ndim == 1, \
            "简单线性回归,只有一维"
        assert len(x_train) == len(y_train)

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

        # 公式,用向量点积
        self.a_ = (x_train - x_mean).dot(y_train - y_mean) / (x_train - x_mean).dot(x_train - x_mean)
        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,返回x的预测结果值"""
        return self.a_ * x_single + self.b_

    def score(self, x_test, y_test):
        """根据测试数据集 x_test 和 y_test 确定当前模型的准确度,使用的是R Square衡量"""

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

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

2回归算法的评价

2.1 三个指标

衡量标准:\sum_1^m(y_{test}^{(i)} - \hat{y_{test}^{(i)}})^2
但是如果不同的样本个数相比,会有问题,因此以下改进

那么RMSE与MAE区别是什么呢?

如果错误值非常大,例如两个样本的差距是100的话,RMSE就扩大到10000的差距了,因此RMSE 能放大 样本中预测结果与真实结果之间较大差异 的趋势,而MAE是没有的。因此从某种程度上讲,让RMSE的值更小相对意义更大,表示样本中错误值最大的比较小。

2.2 最好的线性回归评价指标 R Square

问题引入:假如使用RMSE、MAE预测房价误差是5万元,预测学生成绩误差是10分,那我们得到的模型是预测房价好呢还是学生成绩好呢,我们无法判断,这也是他们的局限性。

从而引入:
R^2 = 1- \frac{SS_{residual}}{SS_{total}} = 1-\frac{\sum_i^m(\hat{y^{(i)}}-y^{(i)})^2}{\sum_i^m(\overline{y}-y^{(i)})^2}

\sum_i^m(\hat{y^{(i)}}-y^{(i)})^2 使用我们训练出来的模型产生的错误

\sum_i^m(\overline{y}-y^{(i)})^2 使用y=\overline{y}预测产生的错误(也称基准模型)

还可以将R^2进行整理下,如下:

R^2 = 1- \frac{SS_{residual}}{SS_{total}} = 1-\frac{\sum_i^m(\hat{y^{(i)}}-y^{(i)})^2}{\sum_i^m(\overline{y}-y^{(i)})^2}=1- \frac{\frac{\sum_i^m(\hat{y^{(i)}}-y^{(i)})^2}{m}} {\frac{\sum_i^m(\overline{y}-y^{(i)})^2}{m}} = 1 - \frac{MSE(\hat{y},y)} {Var(y)}

2.3 代码

import numpy as np
from math import sqrt


def mean_squared_error(y_true, y_predict):
    """MSE"""
    assert len(y_true) == len(y_predict)
    return np.sum((y_true - y_predict)**2) / len(y_true)


def root_mean_squared_error(y_true, y_predict):
    """RMSE"""
    return sqrt(mean_squared_error(y_true, y_predict))


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


def r2_score(y_true, y_predict):
    """R Square"""
    return 1 - mean_squared_error(y_true, y_predict)/np.var(y_true)

3 多元线性回归

x^{(i)} = (X_1^{(i)},X_2^{(i)},...,X_n^{(i)}) :第i个样本的n个特征

y = {θ_0+θ_1x_1+θ_2x_2+...+θ_nx_n}

预测值:\hat{y}^{(i)} = {θ_0+θ_1X_1^{(i)}+θ_2X_2^{(i)}+...+θ_nX_n^{(i)}}

目标:找到θ_0,θ_1,...θ_n使\sum_1^m(y^{(i)}-\hat{y}^{(i)})^2 = \sum_1^m(y^{(i)}-θ_0-θ_1X_1^{(i)}-θ_2X_2^{(i)}-...-θ_nX_n^{(i)})^2尽可能小

3.1 简单变换:

\hat{y}^{(i)} = {θ_0X_0^{(i)}+θ_1X_1^{(i)}+θ_2X_2^{(i)}+...+θ_nX_n^{(i)}} , X_0^{(i)}=1

其中令X_0^{(i)}恒等于1,虚拟的第0个特征,插入到n个特征的第一列

X^{(i)} = (X_0^{(i)},X_1^{(i)},X_2^{(i)},...,X_n^{(i)})

θ = (θ_0,θ_1,θ_2...,θ_n)^T

可以换成向量的点积,写成 \hat{y}^{(i)} = X^{(i)}.θ

上面是第i个向量的预测结果,而所有向量预测结果可以用矩阵表示

X_b的第一列是插入的,虚拟的第0个特征

3.2 推导过程

那么如何求θ = (θ_0,θ_1,θ_2...,θ_n)^T呢,和简单线性回归相似,对所有参数进行求导,令极值=0。

先给结论:
θ = (X_b^TX_b)^{-1} X_b^Ty
推到过程手写了,请看图,不忍直视的请略过

再此也复制吴恩达大神的推导过程:

\theta ={{\left( {X^{T}}X \right)}^{-1}}{X^{T}}y 的推导过程:

J\left( \theta \right)=\frac{1}{2m}\sum\limits_{i=1}^{m}{{{\left( {h_{\theta}}\left( {x^{(i)}} \right)-{y^{(i)}} \right)}^{2}}}
其中:{h_{\theta}}\left( x \right)={\theta^{T}}X={\theta_{0}}{x_{0}}+{\theta_{1}}{x_{1}}+{\theta_{2}}{x_{2}}+...+{\theta_{n}}{x_{n}}

将向量表达形式转为矩阵表达形式,则有J(\theta )=\frac{1}{2}{{\left( X\theta -y\right)}^{2}} ,其中Xmn列的矩阵(m为样本个数,n为特征个数),\thetan行1列的矩阵,ym行1列的矩阵,对J(\theta )进行如下变换

J(\theta )=\frac{1}{2}{{\left( X\theta -y\right)}^{T}}\left( X\theta -y \right)

=\frac{1}{2}\left( {{\theta }^{T}}{{X}^{T}}-{{y}^{T}} \right)\left(X\theta -y \right)

=\frac{1}{2}\left( {{\theta }^{T}}{{X}^{T}}X\theta -{{\theta}^{T}}{{X}^{T}}y-{{y}^{T}}X\theta -{{y}^{T}}y \right)

接下来对J(\theta )偏导,需要用到以下几个矩阵的求导法则:

\frac{dAB}{dB}={{A}^{T}}

\frac{d{{X}^{T}}AX}{dX}=2AX

所以有:

\frac{\partial J\left( \theta \right)}{\partial \theta }=\frac{1}{2}\left(2{{X}^{T}}X\theta -{{X}^{T}}y -{}({{y}^{T}}X )^{T}-0 \right)

=\frac{1}{2}\left(2{{X}^{T}}X\theta -{{X}^{T}}y -{{X}^{T}}y -0 \right)

={{X}^{T}}X\theta -{{X}^{T}}y

\frac{\partial J\left( \theta \right)}{\partial \theta }=0,

则有\theta ={{\left( {X^{T}}X \right)}^{-1}}{X^{T}}y

3.3 代码

θ = (θ_0,θ_1,θ_2...,θ_n)^T

其中θ_0为截距
(θ_1,θ_2...,θ_n)^T 是系数,因为在系数部分,每一个值对应样本的一个特征,可以看到每一个特征的贡献是如何的

import numpy as np

class LinearRegression:

    def __init__(self):
        """初始化Linear Regression模型"""
        self.coef_ = None  # 系数
        self.intercept_ = None  # 截距
        self._theta = None  # θ

    def fit_normal(self, X_train, y_train):
        """根据训练数据集X_train, y_train训练Linear Regression模型"""
        assert X_train.shape[0] == y_train.shape[0]

        # 在X_train矩阵第一列增加全为1的列
        X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
        # 公式θ = (X_T·X)﹣¹·X_T·Y
        self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)

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

    def predict(self, X_predict):
        """给定待预测数据集X_predict,返回表示X_predict的结果向量"""
        assert self.intercept_ is not None and self.coef_ is not None
        assert X_predict.shape[1] == len(self.coef_)

        X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
        return X_b.dot(self._theta)

    def score(self, X_test, y_test):
        """确定当前模型的准确度,使用的是R Square衡量"""

        y_predict = self.predict(X_test)
        return r2_score(y_test, y_predict)


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

小结

下章预告:梯度下降法

声明:此文章为本人学习笔记,课程来源于慕课网:python3入门机器学习经典算法与应用。在此也感谢bobo老师精妙的讲解。

如果您觉得有用,欢迎关注我的公众号,我会不定期发布自己的学习笔记、AI资料、以及感悟,欢迎留言,与大家一起探索AI之路。

AI探索之路
上一篇 下一篇

猜你喜欢

热点阅读