机器学习之线性回归算法详解(附加利福尼亚房价预测的实现源码)

机器学习15_线性回归算法详解 (2021.05.30)

by demo

一. 基础知识
  • 什么是回归问题?回归问题的本质又是什么?
    回归问题其实就是目标值是连续性的值,而分类问题的目标值则是离散型的值。回归处理的问题为预测,其本质都在于根据事物的相关特征预测出对应的结果值。比如:预测房价、预测销售额、设定贷款额度等。

  • 举一个生活中有关回归的例子: 预测学生的期末成绩
    已知了期末成绩的判定方法:0.7 x 考试成绩 + 0.3 x 平时成绩(该公式或者算法在别的线性回归算法中是根据数据推演出来的,而不是提前设置好的)则当知道了一个学生的期末考试的卷面成绩以及平时成绩后,就可以根据这两个特征所占的权重,预测出该学生最终的期末成绩。
    由此可以看出:
    1.回归算法预测出的结果其实就是经过相关的算法计算出来的结果值。
    2.每一个特征都需要有一个权重的占比,这个权重的占比明确了之后,就可以得到最终的计算结果,也就是获取了最终的预测结果了。
    3.也就是说线性回归其实就是在找寻特征和目标数据之间所对应的关联,这个关联则是基于一个权重系数来表示的。

  • 怎么来表示一个线性回归问题?
    一般情况下,都可以用一个线性回归方程来描述一个线性回归问题。而线性回归的线性方程都可以用 y = wx + b 来表示,其中w为斜率,b为截距。那么如果用线性方程表示这个去一组数据的趋势的话,这个b是否需要呢?是否带上这个b,得具体情况具体分析,当b不存在时,如果x为0,则y必定为0,那么就意味着趋势对应的直线必经过坐标系的原点(0,0),如果带上b的话,则直线不过原点。加了b的目的其实是为了使得趋势对应的直线更加具有通用性。(大部分情况下,带上b更好)

  • 正确认识线性回归中的误差
    线性回归预测中难免会出现的问题 ⇒ 真实结果与预测结果存在某些误差!举个例子来说,如果在房价预测案例中,当特征与目标之间的分布规律不是线性的时候,如果非要用一条直线去表示特征与目标之间的趋势并将其作为预测的规律,则一定会引发预测上的误差。但为了满足线性回归的原理,直线是必须要使用的,因此在选择最佳的直线时,只要保证每个散点到直线的距离的累加和是最小的,则就可以将这条直线称为最佳的预测直线。虽然仍会存在误差,但在大多数的预测中都会和真实值存在一定的误差的,那么既然它无法被避免,那么我们应该如何去处理它呢?

  • 如何处理线性回归的误差?
    首先我们必须知道一个回归算法的特性:
    回归算法的本质其实是一个迭代算法,所谓的迭代算法就好比计算机的版本,win7总比win96好, win8总比win7好,而win10总比win8好。也就是说,在开始训练线性回归模型的时候,是逐步将样本数据带入到模型中对其进行训练的。训练的开始先用部分的样本数据训练模型生成一组w和b,如果对应直线与数据对应的散点的误差比较大,则通过不断地带入样本数据,对模型进行训练,从而会逐步将之前误差较大的w和b值变得越来越精准。
    官方是这么对迭代进行解释的:迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标和结果,每一次对过程的重复成为一次迭代,而每一次迭代得到的结果会作为下一次迭代的初始值。
    ⇒ 误差的处理方法:通俗点说,回归算法就是在不断地自身迭代来减少误差,从而使得回归算法的预测结果可以越发逼近真实的结果。

  • 那么怎么去表示误差呢? ⇒ 使用损失函数
    by demo
    从而推出了权重向量w对误差的大小有着最为密切的关联的!因此关于降低误差的问题就转化成了如何去求解方程中的w使得误差可以最小!
    线性回归所对应的损失函数又被成为:误差平方和(SSE - sum of squared error)或者残差平方和(RSS - Residual sum of squared)

  • 什么是L2范式?
    L2范式的本质就是欧式距离,即是两个向量上的每个点对应相减后的平方再开平方,损失函数只实现了向量上每个点对应相减后的平方和,并没有进行开方处理,所以损失函数就是L2范式(欧式距离公式)的平方结果。
    by demo

  • 最小二乘法
    从上述分析中得出为了使得损失函数最小化,就必须最小化参数向量w,那么如何才能实现参数向量w的最小化呢? 答案就是最小二乘法!具体实现方法如下:
    by demo
    最小二乘法的API:from sklearn.learn_model import LinearRegression
    参数介绍:(可看可不看)
    fit_intercept:布尔值,可不填,默认为True。表示是否计算此模型的截距,如果设置为False则不会计算截距。
    normalize:布尔值,可不填,默认为False。表示当设置为False时,将忽略此参数,如果为True,则特征矩阵在进入回归前将会被减去均值(中心化)并除以L2范式(缩放),如果你希望对特征矩阵进行标准化,则需要在fit数据之前,使用preprocessing模块中的标准化专用类StandardScaler (注:一般情况下,在回归模型中是不需要对特征进行归一化或者标准化处理的)。
    copy_X:布尔值,可不填,默认为True。如果为真,将在X.copy()上进行操作,否则的话原本的特征矩阵X可能被线性回归影响并覆盖。
    n_jobs: 整数或者None,可不填,默认为None。如果表示一个整数值的话,则表示使用全部的CPU进行计算我们线性回归所需要的运算,那么如果同时还在计算机上进行其他操作,则其他操作就会卡顿。
    根据参数可以发现:这些参数中没有一个是必须填的,更没有对我们模型有不可替代作用的参数,这说明线性回归的性能,往往取决于数据本身,而并非我们调参的能力,也正是因此,线性回归对数据有着很高的要求。幸运的是,现实中大部分连续变量之间都存在多多少少的线性联系,所以线性回归虽然简单,但功能很强大。而且,sklearn中的线性回归可以处理多标签问题,只需要在fit的时候输入多维度标签就可以了。

  • 线性回归的评价方法
    回归算法的模型评估一直都是回归算法的一个难点,回归型算法与分类型算法的模型评估其实有着相似的法则,即找寻真实标签和预测值的差异。只不过在分类型算法中,这个差异只需要一种角度来评判就可以了,那就是是否预测到了正确的分类。然而在回归型算法中,我们需要从以下两个角度来看待回归的效果:
    1.我们是否预测到了正确或者接近正确的数值?(因为有误差的存在)
    2.我们是否拟合到了足够多的信息,即模型预测结果的线性和样本的真实结果的线性是否更加吻合?

  • 线性回归评价方法的各个击破
    一. 我们是否预测到了正确或者接近正确的数值(因为有误差的存在)?
    ⇒ 使用残差平方和(RSS)的变形 : 均方误差(公式如下)
    by demo
    均方误差(MSE)的本质其实就是在残差平方和的基础上除以了样本总量,得到了每个样本量上的平均误差,有了平均误差,我们就可以将平均误差和我们标签的取值范围(最大值和最小值)在一起比较,从此获得一个较为可靠的评估依据(即可以查看这个误差有多严重)在sklearn中,我们有两种方式调用这个评估指标。
    1.使用sklearn专用的模型评估模块metrics里的类:mean_squared_error
    2.调用交叉验证的类cross_val_score并将里面的scoring参数设置为:neg_mean_squared_error
    二.我们是否拟合到了足够多的信息,即模型预测结果的线性和样本的真实结果的线性是否更加吻合?
    对于回归算法而言,只探索数据预测是否准确是不足够的,除了数据本身的数值大小之外,我们还希望我们的模型能够捕捉到数据的规律,比如数据的分布规律(抛物线)、单调性等,而是否捕获到了这些信息是无法用均方误差(MSE)来衡量的。用下边的这张图进行说明:
    by demo如图所示,红色曲线表示我们的真实标签,蓝色曲线表示模型预测的结果,在黄色点之前的部分,可以看出来拟合的是比较成功的,但从黄色点之后开始,明显可以看出来,模型预测的结果与真实标签有着越来越大的差异,但由于均方误差(MSE)是将所有的误差加起来再做平均,由于大部分的预测结果与真实标签的误差不是很大,所以导致平均下来之后从均方误差很难看出来黄色点之后的预测结果是不准确的,因此就需要进行模型与样本真实结果的拟合判断。拟合程度则可以通过下边的公式来表示:
    by demo
    在该公式中,分式的分子是真实值与预测值之间的差值,也就是我们模型没有捕获到的信息总量,分母是真实标签所带的信息量,所以如果拟合程度越好,则该分式的分子越接近于0,整个分式也就越接近0,而整个公式的结果就越接近1。
    ⇒ 调用方法:一种是直接从metrics中导入r2_score,输入预测值和真实值后打分;一种是直接从线性回归LinearRegression的接口score进行调用;还有一种是在交叉验证中输入r2来调用。

二. 基于线性回归算法的加利福尼亚房价预测代码实现
"""线性回归预测加利福尼亚房价"""

from sklearn.linear_model import LinearRegression  # 最小二乘法
from sklearn.model_selection import train_test_split  # 数据集的划分
from sklearn.datasets import fetch_california_housing as fch  # 加利福尼亚房屋价值的数据集
from sklearn.metrics import mean_squared_error  # 用于评估回归结果的误差
from sklearn.model_selection import cross_val_score  # 用于使用交叉验证评估回归结果的误差
from sklearn.metrics import r2_score  # 用于评估回归曲线与真实曲线的拟合度
import matplotlib.pyplot as plt  # 用于绘制拟合图

# 提取样本数据集
feature = fch().data
target = fch().target
print(feature.shape)
print(target.shape)

# 因为在线性回归中一般不需要做特征预处理操作,则将该步骤省略

# 进行数据集的拆分
x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.1, random_state=2021)

"""对拆分好的数据集进行训练"""
# 模型的实例化
linear = LinearRegression()  # 参数都使用默认值
# 训练
linear.fit(x_train, y_train)
# 根据特征的数量返回相应数量的w
print(linear.coef_)
# 返回截距
print(linear.intercept_)
# 将求解出的w和特征数据的名称放到一起展示
print([*zip(fch().feature_names, linear.coef_)])

# 结果  可以从权重的大小看出来,AveBedrms对目标数据的影响最大
# [('MedInc', 0.43533899655127006),    街区住户收入的中位数
# ('HouseAge', 0.009258750183356396),   房屋使用年数的中位数
# ('AveRooms', -0.10731055672857288),   街区平均房屋的数量
# ('AveBedrms', 0.6507905480977392),   该街区平均的卧室数目
# ('Population', -3.895951041093387e-06),   街区人口
# ('AveOccup', -0.004080762018832711),   平均入住率
# ('Latitude', -0.42398540836226223),   街区的纬度
# ('Longitude', -0.43808139154567377)]  街区的精度

"""对回归模型的结果进行评估"""
# 第一步(方法1) 从 是否预测到了正确或者接近正确的数值 的角度去评估线性回归的结果(使用sklearn中的专有评估模型mean_squared_error实现均方误差的计算)
y_true = y_test  # 测试集的真实标签结果
y_pred = linear.predict(x_test)  # 使用线性回归预测的结果
average_error = mean_squared_error(y_true, y_pred)
print("平均误差值为", average_error)
print("真实目标标签的最大值:", y_true.max(), "真实目标标签的最小值", y_true.min())
print("平均误差值是标签数据最大值的:", average_error / y_true.max() * 100, "%")
print("平均误差值是标签数据最小值的:", average_error / y_true.min() * 100, "%")

# 第一步(方法2) 从 是否预测到了正确或者接近正确的数值 的角度去评估线性回归的结果(使用交叉验证实现均方误差计算)
average_error2 = cross_val_score(linear, x_train, y_train, cv=5, scoring='neg_mean_squared_error').mean()
print(average_error2)  # 算出结果的符号只是代表损失的意思,而并没有任何数值的意义

# 第二步(方法1) 从是否拟合到了足够多的信息,即模型预测结果的线性和样本的真实结果的线性是否更加吻合的角度去评估线性回归的结果(sklearn.metrics)
matching_eval = r2_score(y_test, linear.predict(x_test))
print(matching_eval)

# 第二步(方法2) 从是否拟合到了足够多的信息,即模型预测结果的线性和样本的真实结果的线性是否更加吻合的角度去评估线性回归的结果(linear.score)
matching_eval2 = linear.score(x_test, y_test)
print(matching_eval2)

# 第二步(方法3) 从是否拟合到了足够多的信息,即模型预测结果的线性和样本的真实结果的线性是否更加吻合的角度去评估线性回归的结果(cross_val_score)
matching_eval3 = cross_val_score(linear, x_train, y_train, cv=10, scoring='r2').mean()
print(matching_eval3)

"""绘制拟合图"""
y_pred = linear.predict(x_test)
plt.plot(range(len(y_test)), sorted(y_test), c="red", label="True")
plt.plot(range(len(y_pred)), sorted(y_pred), c="black", label="Predict")
plt.legend()
plt.show()

拟合图:

by demo


如有问题,敬请指正。欢迎转载,但请注明出处。
  • 4
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值