线性回归

线性回归算法

  • 解决回归问题
  • 形式简单、易于建模
  • 蕴含着机器学习中一些重要的基本思想
  • 许多强大的非线性模型的基础

线性模型

给定由 d d d 个属性描述的示例

x = ( x 1 ; x 2 ; x 3 ; . . . ; x d ) x = (x_1;x_2;x_3;...;x_d) x=(x1;x2;x3;...;xd)

其中 x i x_i xi x x x 在第 i i i 个属性上的取值

线性模型试图学得一个通过属性的线性组合来进行预测的函数,即

f ( x ) = a 1 x 1 + a 2 x 2 + . . . + a d x d + b f(x) = a_1x_1 + a_2x_2 + ... + a_dx_d + b f(x)=a1x1+a2x2+...+adxd+b

一般用向量形式写成

f ( x ) = a T x + b f(x) = a^Tx + b f(x)=aTx+b

其中 a = ( a 1 ; a 2 ; . . . ; a d ) a = (a_1;a_2;...;a_d) a=(a1;a2;...;ad). a a a b b b 学得之后,模型就得以确定


数据集 : D = ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) , . . . . , ( x m , y m ) D={(x_1, y_1),(x_2,y_2),(x_3,y_3),....,(x_m,y_m)} D=(x1,y1),(x2,y2),(x3,y3),....,(xm,ym),

x i = ( x i 1 ; x i 2 ; x i 3 ; . . . ; x i d ) x_i = (x_{i1};x_{i2};x_{i3};...;x_{id}) xi=(xi1;xi2;xi3;...;xid), y i = R y_i=\mathbb{R} yi=R .

​ 其中 x i x_i xi x x x 在第 i i i 个属性上的取值.


简单线性回归

我们先考虑一种最简单的情形:输入属性的数目只有一个。即

D = ( x i , y i ) i = 1 m D = {(x_i, y_i)}_{i=1} ^{m} D=(xi,yi)i=1m

x i ∈ R x_i\in \mathbb{R} xiR

线性回归试图学得

f ( x i ) = a x i + b f(x_i) = ax_i + b f(xi)=axi+b, 使得 f ( x i ) ≃ y i f(x_i) \simeq y_i f(xi)yi

​ 其中 f ( x i ) f(x_i) f(xi) 可写成 y i ^ \hat{y_i} yi^

如图:

在这里插入图片描述

如何确定 a a a b b b 呢? 关键在与如何衡量 y i ^ \hat{y_i} yi^ y y y 之间的差别。如图:

在这里插入图片描述

上图所示,

我们先考虑让 y i ^ \hat{y_i} yi^ y y y 之间的差距,当值为 0 时,直线完全拟合数据。我们希望如此,但这是不可能的。

我们又考虑让 y i ^ \hat{y_i} yi^ y y y 之间的绝对值,绝对值的函数并不是处处可导的,所以也不取。

最后,我们选择 y i ^ \hat{y_i} yi^ y y y 差的平方,考虑到全部样本。

在这里插入图片描述


目标:找到 a a a b b b,使得 E ( a , b ) = ∑ i = 1 m ( y i − a x i − b ) 2 E(a, b) = \sum_{i=1}^{m}(y_i - ax_i - b)^2 E(a,b)=i=1m(yiaxib)2 尽可能地小

令损失函数 E ( a , b ) E(a, b) E(a,b) 导后为 0,就能得到最优解

最小二乘法解决:

a = ∑ i = 1 m ( x i − x ˉ ) ( y i − y ˉ ) ∑ i = 1 m ( x i − x ˉ ) 2 a = \frac{\sum_{i=1}^{m}(x_i - \bar{x})(y_i - \bar{y})}{\sum _{i=1}^{m}(x_i - \bar{x})^2} a=i=1m(xixˉ)2i=1m(xixˉ)(yiyˉ)

b = y ˉ − a x ˉ b = \bar{y} - a\bar{x} b=yˉaxˉ

​ 其中 x ˉ = 1 m ∑ i = 1 m x i \bar{x} = \frac{1}{m}\sum_{i=1}^{m}x_i xˉ=m1i=1mxi x x x 的均值


代码实现:简单线性回归

import numpy as np
import matplotlib.pyplot as plt

class LinearRegression1(object):
    def __init__(self):
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        # 简单线性回归器只能求解单一特征训练数据
        assert x_train.ndim == 1, \
            "Simple Linear Regressor can only solve single feature training data"
        assert len(x_train) == len(y_train), \
        "the size of x_train must be to the szie of equal y_train"
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)
        num = 0.0
        d = 0.0
        for x, y in zip(x_train, y_train):
            num += (x - x_mean) * (y - y_mean)
            d += (x - x_mean) ** 2
        self.a_ = num / d
        self.b_ = y_mean - self.a_ * x_mean
        return self

    def predict(self, x_predict):
        assert x_predict.ndim == 1, \
            "Simple Linear Regressor can only solve single feature training data"
        assert self.a_ is not None and self.b_ is not None, \
            "the size of x_train must be to the szie of equal y_train"
        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 "Simple Linear Regression1()"


if __name__ == '__main__':
    x = np.array([1., 2., 3., 4., 5.])
    y = np.array([1., 3., 2., 3., 5.])
    lrg = LinearRegression1()
    lrg.fit(x, y)
    y_hat = lrg.predict(x)
    plt.scatter(x, y)
    plt.plot(x, y_hat, c='r')
    plt.show()

如图:

在这里插入图片描述

对于上面代码所使用的 for 对单个变量循环来说,我们使用一种更为常用且快速的方法 向量运算


对于 ∑ i = 1 m ( y i − a x i − b ) 2 \sum_{i=1}^{m}(y_i - ax_i - b)^2 i=1m(yiaxib)2

a = ∑ i = 1 m ( x i − x ˉ ) ( y i − y ˉ ) ∑ i = 1 m ( x i − x ˉ ) 2 a = \frac{\sum_{i=1}^{m}(x_i - \bar{x})(y_i - \bar{y})}{\sum _{i=1}^{m}(x_i - \bar{x})^2} a=i=1m(xixˉ)2i=1m(xixˉ)(yiyˉ)

b = y ˉ − a x ˉ b = \bar{y} - a\bar{x} b=yˉaxˉ

∑ i = 1 m w i ⋅ v i \sum_{i=1}^{m}w_i \cdot v_i i=1mwivi

其中 w i = ( w 1 ; w 2 ; w 3 ; . . . w m ) w_i = (w_1;w_2;w_3;...w_m) wi=(w1;w2;w3;...wm)

v i = ( v 1 ; v 2 ; v 3 ; . . . v m ) v_i = (v_1;v_2;v_3;...v_m) vi=(v1;v2;v3;...vm)

w ⋅ v w \cdot v wv

num = (x_train - x_mean).dot(y_train - y_mean)
d = (x_train - x_mean).dot(x_train - x_mean)

多元线性回归

更为常见的情形是如开头的数据集 D D D,样本由 d d d 个属性来描述,此时我们试图学得

y i ^ = θ 1 x 1 + θ 2 x 2 + . . . + θ d X d + b \hat{y_i} = \theta_1x_1 + \theta_2x_2 + ... + \theta_dX_d + b yi^=θ1x1+θ2x2+...+θdXd+b

b b b截距 ( θ 1 ; . . . ; θ d ) (\theta_1;...;\theta_d) (θ1;...;θd)系数 ,将 b b b 写为 θ 0 \theta_0 θ0,并将 x 0 x_0 x0 设为 1,得到

y i ^ = θ 0 x 0 + θ 1 x 1 + θ 2 x 2 + . . . + θ d X d \hat{y_i} = \theta_0x_0 + \theta_1x_1 + \theta_2x_2 + ... + \theta_dX_d yi^=θ0x0+θ1x1+θ2x2+...+θdXd

所以我们的目标为

​ 找到 θ 0 , θ 1 , . . . , θ d \theta_0, \theta_1, ..., \theta_d θ0,θ1,...,θd,使得 ∑ i = 0 m ( y i − y i ^ ) 2 \sum_ {i=0} ^{m}(y_i - \hat{y_i})^2 i=0m(yiyi^)2,尽可能地小

θ = ( θ 0 ; θ 1 ; . . . ; θ d ) \theta = (\theta_0;\theta_1;...;\theta_d) θ=(θ0;θ1;...;θd) θ \theta θ 是一个一维向量,我们习惯把一维向量看为列向量 表示

对此,我们想要使得 θ \theta θ 点乘 X X X ,得到

f ( x i ) = θ T x i f(x_i) = \theta^Tx_i f(xi)=θTxi

y ^ = θ T ⋅ X \hat{y} = \theta^T \cdot X y^=θTX

那么对于多元函数公式有

θ = ( y − X θ ) T ( y − X θ ) \theta = (y - X\theta)^T(y - X\theta) θ=(yXθ)T(yXθ)

( y − X θ ) T ( y − X θ ) (y - X\theta)^T(y - X\theta) (yXθ)T(yXθ) 尽可能地小,得到

θ = ( X T X ) − 1 X T y \theta = (X^TX)^{-1}X^Ty θ=(XTX)1XTy

问题:时间复杂度高: O ( n 3 ) ( 优 化 O ( n 2.4 ) ) O(n^3)(优化 O(n^{2.4})) O(n3)(O(n2.4))

优点:不需要对数据做归一化处理

代码:

import numpy as np
from blog_metrics import r2_score
import matplotlib.pyplot as plt
import sklearn.datasets as datasets
from sklearn.model_selection import train_test_split


class LinearRegression(object):
    def __init__(self):
        self.coef_ = None
        self.interception_ = None
        self._theta = None

    def fit_normal(self, X_train, y_train):
        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])
        # np.c_[np.ones((len(X), 1)), X]

        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):
        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_predict"

        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):
        y_predict = self.predict(X_test)
        return r2_score(y_test, y_predict)

    def __repr__(self):
        return "Linear Regression"


if __name__ == '__main__':
    bost = datasets.load_boston()

    x = bost.data
    y = bost.target

    X = x[y < 50]
    y = y[y < 50]

    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

    lrg = LinearRegression()
    lrg.fit_normal(X_train, y_train)

    # 系数
    print(lrg.coef_)
    # 截距
    print(lrg.interception_)

    # R^2 值
    print(lrg.score(X_test, y_test))

拓展

一类机器学习算法的基本思路

我们所谓的建模就是指 找到一个模型最大程度地拟合我们的数据,在线性模型中就是直线方程。最大拟合数据其本质就是找到一个函数。在 ∑ i = 1 m ( y i − a x i − b ) 2 \sum_{i=1}^{m}(y_i - ax_i - b)^2 i=1m(yiaxib)2 中就是指 损失函数(loss function),度量出模型没有拟合出我们的样本的一部分。另一种时度量出拟合的部分,称 效用函数(utility function)

在这里插入图片描述

近乎所有参数学习算法都是这样的套路,如

线性回归、多项式回归、路基回归、SVM、神经网络…

性能度量

对模型的泛化性能进行评估,不仅需要有效可行的实验估计方法,还要有衡量模型泛化能力的评价标准,这就是性能度量(performance measure)

性能度量反映了任务需求,再对比不同的模型的能力时,使用不同的性能度量往往会导致不同的评判结果。这意味着模型的好坏是相对的,什么样的模型是好的,不取决于算法和数据,还决定于任务需求。

在预测任务中:

数据集: D = ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) , . . . . , ( x m , y m ) D={(x_1, y_1),(x_2,y_2),(x_3,y_3),....,(x_m,y_m)} D=(x1,y1),(x2,y2),(x3,y3),....,(xm,ym)

y i y_i yi 是样本 x i x_i xi 的真实标记。要评估模型的 性能,就要把预测结果 y ^ \hat{y} y^ y y y 进行比较。

回归任务最常用的性能度量是 均方误差(MSE)

均方误差(MSE)

1 m ∑ i = 1 m ( y i − y i ^ ) 2 \frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y_i})^2 m1i=1m(yiyi^)2

均方根误差

1 m ∑ i = 1 m ( y i − y i ^ ) 2 = M S E \sqrt{\frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y_i})^2} = \sqrt{MSE} m1i=1m(yiyi^)2 =MSE

平方绝对误差

1 m ∑ i = 1 m ∣ y i − y i ^ ∣ \frac{1}{m}\sum_{i=1}^{m}\left | y_i - \hat{y_i} \right | m1i=1myiyi^

虽然平方绝对误差不能用来进行预测,但是它可以用来评测算法的好坏。

R Squared 广泛使用

R 2 = 1 − ∑ i ( y i ^ − y i ) 2 ∑ i ( y ˉ − y i ) 2 R^2 = 1 - \frac{\sum_i (\hat{y_i} - y_i)^2}{\sum_i(\bar{y} - y_i)^2} R2=1i(yˉyi)2i(yi^yi)2

∑ i ( y i ^ − y i ) 2 \sum_i (\hat{y_i} - y_i)^2 i(yi^yi)2 使用我们的模型预测产生的错误

∑ i ( y ˉ − y i ) 2 \sum_i(\bar{y} - y_i)^2 i(yˉyi)2 使用 y = y ˉ y = \bar{y} y=yˉ 预测产生的错误, y y y 的方差

  • R 2 R^2 R2 <= 1

    R 2 R^2 R2 越大越好,当我们的预测模型不犯任何错误时, R 2 R^2 R2 得到最大值 1

  • R 2 = 0 R^2 = 0 R2=0

    当我们的模型等于基准模型时, R 2 R^2 R2 为 0

  • R 2 R^2 R2 < 0

    我们的数据很有可能不存在任何线性关系

def mean_squared_error(y_true, y_predict):
    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):
    return sqrt(mean_squared_error(y_true, y_predict))


def mean_absolute_error(y_true, y_predict):
    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_true - y_predict)) / len(y_true)


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

参考:

  • 西瓜书-第三章 线性模型
  • imooc python3入门机器学习https://coding.imooc.com/class/chapter/169.html#Anchor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值