目录

0x00 简单的线性回归

0x01 最小二乘法(高数复习)

0x02 简单线性回归的编程实现

0x03 向量化

0x04 衡量线性回归法的指标:MSE,RMSE,MAE

0x05 最好的衡量线性回归发的指标R Squared

0x06 多元线性回归

0x07 实现多元线性回归

0x08 使用 scikit-learn 解决回归问题

0x09 线性回归模型的可解释性

线性回归算法总结:


0x00 简单的线性回归

思路:

假设样本特征 和 样本标记 之间存在线性关系,我们只要寻找到一条直线,可以最大程度的拟合样本特征和样本标记之间的关系,就可以使用该直线 对一个新样本的标记进行预测

例如:房屋面积和价格之间就可能存在这样一条直线,我们只要找到该直线方程,输入新样本的房屋面积就可以预测出房屋的价格

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归

注意线性回归问题和线性分类问题坐标轴的区别:

分类问题中,横轴和纵轴都是样本特征,

回归问题中,纵轴是样本标记,横轴是样本特征

线性回归分析变量显著性t值 线性回归显著性为0_极值_02

因为在回归问题中,样本特征并不是离散的,而是连续的数值,所以不能用不同颜色来表示,只能用一个坐标轴来表示

那么什么是简单线性回归呢?

样本特征只有一个的线性回归,我们称为简单线性回归

以房屋面积和房屋价格之间的线性回归问题为例,我们求解下该问题的最佳拟合直线方程

线性回归分析变量显著性t值 线性回归显著性为0_极值_03

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_04

这里之所以用平方距离,而不是绝对值距离,是因为绝对值难以求导,不容易求极值。

线性回归分析变量显著性t值 线性回归显著性为0_极值_05

以上过程体现了一类机器学习算法的基本思路:

机器学习建模其实就是找到一个模型最大程度拟合我们的数据,而找到一个模型就是在找一个最优化的目标函数。

而目标函数可以分为两类:

损失函数:衡量 准确度损失,我们希望尽可能的小

效用函数:衡量 算法的准确度,我们希望尽可能的大

通过分析问题,我们可以确定问题的损失函数或者效用函数,通过最优化损失函数或者效用函数,获得机器学习的模型。

其中最优化损失函数,往往是在求该损失函数的最小值。

最优化效用函数,往往是在求该效用函数的最大值。

近乎所有参数学习算法(线性回归、多项式回归、逻辑回归、SVM、神经网络等)都是这样的套路。

0x01 最小二乘法(高数复习)

因为线性回归问题具有唯一的极值点,所以求该函数的最小值就可以直接转化为求该函数的极值点的问题:

多元函数求极值点,只要对每个元求偏导,让偏导等于 0, 即可求出该多元函数的极值点处 每个元对应的值

先给出推导结果如下:

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_06

以下是具体的推导过程:

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_07

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_08

线性回归分析变量显著性t值 线性回归显著性为0_极值_09

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_10

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_11

0x02 简单线性回归的编程实现

线性回归分析变量显著性t值 线性回归显著性为0_极值_12

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_13

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_14

封装成类库:

# 简单线性回归

import numpy as np


class SimpleLinearRegression1:
    def __init__(self):
        # 命名规范:下划线结尾,因为a和b不是用户送进来的参数,而是我们算法计算出来的
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        assert 1 == x_train.ndim,\
            "x_train必须是一个向量"
        assert len(x_train) == len(y_train),\
            "x_train 和 y_train 元素个数必须相等"

        num = 0.0  # 分子初始化
        d = 0.0  # 分母初始化
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)
        for x_i, y_i in zip(x_train, y_train):  # 将x,y先打包成元组列表
            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

    # 给定预测数据集x_predict,返回表示y_predict 的结果向量
    def predict(self, x_predict):
        assert 1 == x_predict.ndim,\
            "x_predict必须是一个向量"
        assert self.a_ is not None and self.b_ is not None,\
            "predict前请先fit"
        return np.array([self._predict(x) for x in x_predict])
    
    def _predict(self,x_single):
        y_predict = self.a_ * x_single +self.b_
        return y_predict

测试类库:

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_15

0x03 向量化

向量点乘 = 两个向量对应的元素相乘再相加 ,其实就是 向量版的矩阵乘法

线性代数(同济版)p31页,一个1xs行的矩阵 和 一个sx1列的矩阵相乘 就是一个1阶方阵,也就是一个数

线性回归分析变量显著性t值 线性回归显著性为0_极值_16

这样一来就可以将需要用for循环来算的累加 转化为 numpy中向量点乘,而后者的速度要比前者快很多倍

只需要修改fit函数中的for循环部分:

def fit(self, x_train, y_train):
        assert 1 == x_train.ndim,\
            "x_train必须是一个向量"
        assert len(x_train) == len(y_train),\
            "x_train 和 y_train 元素个数必须相等"

        num = 0.0  # 分子初始化
        d = 0.0  # 分母初始化
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)
        # for x_i, y_i in zip(x_train, y_train):  # 将x,y先打包成元组列表
        #     num += (x_i - x_mean)*(y_i-y_mean)
        #     d += (x_i - x_mean)**2
        num = (x_train-x_mean).dot(y_train-y_mean) #1xs的行向量 * sx1的列向量
        d = (x_train-x_mean).dot(x_train-x_mean)
        self.a_ = num / d
        self.b_ = y_mean - self.a_ * x_mean
        return self

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_17

性能测试:性能上几乎提升了150倍

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_18

0x04 衡量线性回归法的指标:MSE,RMSE,MAE

对于简单线性回归来说:

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_19

但是上述衡量标准是和m相关的,所以我们需要将m消掉

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_20

但是上述衡量标准也有一个问题,比如说y的量纲是元,那么最终MES的量纲就是 元的平方,很不舒服

所以我们再开根号,让衡量标准的量纲和y的量纲保持一致,让误差的意义更加明显

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_21

除此之外,还有一个更加直白的评测标准:

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_22

编程实现:

线性回归分析变量显著性t值 线性回归显著性为0_极值_23

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_24

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_25

封装成函数:metrics.py

import numpy as np
from math import sqrt 

#计算y_true和y_predict的重合度
def accuracy_score(y_true,y_predict):
    return sum(y_true == y_predict)/len(y_true)

#mse
def mean_squared_error(y_true,y_predict):
    return np.sum((y_true-y_predict)**2) / len(y_true)

#rmse
def root_mean_squared_error(y_true,y_predict):
    return sqrt(mean_squared_error(y_true,y_predict))

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

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_26

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_27

为什么RMSE 比MAE 大?

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_28

因为RMSE 先做了平方,所以RMSE有放大误差的趋势,特别是最大误差值的占比会扩大

0x05 最好的衡量线性回归发的指标R Squared

我们之前衡量分类准确度:1 最好 0 最差,但是mse、amse、mae等衡量指标却没有这样的性质

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_29

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_30

线性回归分析变量显著性t值 线性回归显著性为0_极值_31

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_32

线性回归分析变量显著性t值 线性回归显著性为0_极值_33

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

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_34

0x06 多元线性回归

多元线性回归可以理解为简单线性回归的推广,将原来 y = ax +b

推广到 :

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_35

线性回归分析变量显著性t值 线性回归显著性为0_极值_36

求解多元线性回归的思路 和简单线性回归也是一样的:

使预测结果 结果和真实结果 之间的差距尽可能的小

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_37

只不过:

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_38

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_39

为了使这个式子推导起来更加方便,我们可以给x(i) 虚构一个第0个特征

该特征恒等于1,这样就可以将下式子变形为:

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_40

将θ 和 X(i)都表示成向量形式之后,我们就可以发现:

y(i)冒 不就是是 θ 和X(i) 进行矩阵乘法的结果吗?

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_41

对于第i个样本的预测值有如上公式,那么我们还可以进一步推广到所有样本上

线性回归分析变量显著性t值 线性回归显著性为0_极值_42

注意:这里我们将 原来的参数矩阵称为X,在原来参数的基础上添加一列1得到的矩阵称为Xb

线性回归分析变量显著性t值 线性回归显著性为0_极值_43

这里的推倒过程已经超过了本科线性代数的范围,这里暂时省略推倒过程

直接给出结果,这个结果不需要背,需要用的时候百度就可以

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_44

线性回归分析变量显著性t值 线性回归显著性为0_极值_45

0x07 实现多元线性回归

线性回归分析变量显著性t值 线性回归显著性为0_线性回归_46

import numpy as np
from .metrics import r2_score

class LinearRegression:
    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],\
            "X_train中的样本数量和y_train中的标记数量必须相等"
        X_b =np.hstack([np.ones((len(X_train),1)),X_train]) 
        #给X_train左边加上1列,全是1 => np.ones( (len(X_train),1) ) 行数和X_train一样,列数为1
        #直接套用公式
        self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)
        #复习一下:np.linalg.inv() 求矩阵的逆
        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,\
            "在predict之前请先fit"
        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):
        y_predict = self.predict(X_test)
        return r2_score(y_test,y_predict)
    def __repr__(self):
        return "LinearRegression()"

线性回归分析变量显著性t值 线性回归显著性为0_极值_47

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_48

0x08 使用 scikit-learn 解决回归问题

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_49

使用knn算法同样可以解决线性回归问题:

线性回归分析变量显著性t值 线性回归显著性为0_线性回归分析变量显著性t值_50

knn算法有许多超参数,我们用网格搜索 选出最佳超参数,看能不能提高预测准确度

线性回归分析变量显著性t值 线性回归显著性为0_极值_51

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_52

注意:网格搜索在选择最佳超参数的时候评价标准并不是 r2_score ,而是使用交叉验证的方法,所以

选择出来的超参数不见得是r2_score标准下预测准确率最高的超参数。

0x09 线性回归模型的可解释性

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_53

系数的正负表示正相关还是负相关,系数的大小代表了该特征对结果影响程度的大小

线性回归分析变量显著性t值 线性回归显著性为0_极值_54

具体各个特征表示什么意义如下:

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_55

线性回归算法总结:

线性回归算法是典型的参数学习

而kNN算法是典型的非参数学习

线性回归算法只能解决回归问题,虽然很多分类方法中,线性回归是基础(例如:逻辑回归)

对比kNN算法:既可以解决分类问题 又可以解决回归问题

我们在使用线性回归算法时,其实是对数据有一个假设的:我们假设特征矩阵 和 结果向量之间存在一个线性关系。

对比kNN算法:我们对数据没有任何假设

线性回归算法是一个白盒子算法:线性回归算法的结果具有很强的解释性,我们可以真正从中学到知识

上述使用的线性回归算法使用的是 正规方程解:

线性回归分析变量显著性t值 线性回归显著性为0_多元线性回归_56

可以用 梯度下降法 进一步优化