【线性回归】
1、简介
线性回归是机器学习中非常重要的一个基础知识,线性回归是利用回归方程(函数) 对 一个或多个自变量(特征值)和因变量(目标值)之间 关系进行建模的一种分析方式。它包括了一元线性回归和多元线性回归,一元线性回归指的是:目标值(因标量)只与一个特征(自变量)有关系;多元线性回归指的是:目标值(因标量)同时与多个特征(自变量)有关系。
在机器学习中线性回归的回归方程一般形式为: y = w T x + b y = w^Tx + b y=wTx+b
其中 w w w表示权重参数, b b b表示偏置。
这里的 w w w其实一般情况下是一个矩阵,
我们可以看到转置之后的相乘正好可以展开为:
的形式。上式中的 w w w是一个将偏置b写入的增广矩阵, x x x增广一个 1 也是为了在展开时正好可以拿出偏置 b。
线性回归的图大致可以看成:
当然这是针对一元的。我们其实可以发现它所采用的表示方式与SVM非常类似,但是在SVM中我们需要求解的问题是划分类别,也即找到直线、平面或超平面,而在这里我们是要拟合数据。
2、接口使用
在python中,我们可以很容易的使用标准库中的API简单的实现这一操作。
sklearn.linear_model.LinearRegression()
fit()
predict()
具体的使用方法是:
python
from sklearn.linear_model import LinearRegression
x_data = [[160],[166],[172],[174],[180]]
y_data = [56.3,60.6,65.1,68.5,75]
linear_model = LinearRegression(fit_intercept=True)
linear_model.fit(x_data, y_data)
print(linear_model.intercept_) # 偏置
print(linear_model.coef_) # 斜率
test = [[176]]
res = linear_model.predict(test)
print(res)
主要参数:
c
fit_intercept (bool, default=True):
是否计算截距(b)。如果设置为 True(默认值),则回归模型将包含截距项。如果设置为 False,则模型将强制通过原点(即截距为0)。
normalize (bool, default=False):
在拟合模型之前是否对输入数据进行归一化。已被弃用(从 scikit-learn 0.24 版本开始不推荐使用),建议使用 StandardScaler 或其他标准化方法对数据进行预处理。
copy_X (bool, default=True):
是否复制输入数据 X。如果设置为 True,则在训练时会复制 X,避免对输入数据的修改。如果设置为 False,则在训练时不会复制数据,直接在原始数据上操作。
n_jobs (int, default=None):
用于计算的CPU核心数。n_jobs=-1 表示使用所有可用的核心。这个参数主要在处理大量数据时加速计算,但对于 LinearRegression 来说,它只在某些特殊情况(例如并行计算矩阵分解时)有用。
positive (bool, default=False):
如果设置为 True,则所有回归系数和截距都会被约束为非负值(即所有系数和截距都不能为负)。
接口所提供的方法:
c
fit(X, y):拟合线性回归模型。
X:训练数据(二维数组,形状为 (n_samples, n_features))。
y:目标值(标签),一维数组,形状为 (n_samples,)。
predict(X):根据训练好的模型对新数据进行预测,返回预测结果。
X:特征数据。
score(X, y):返回模型的 R² 分数(决定系数),衡量模型的拟合优度。
X:测试特征数据。
y:测试目标值。
get_params():获取模型的所有超参数。
set_params():设置模型的超参数。
当然它内置了一些属性可以让我们查看权重和偏置等:
Bash
coef_:拟合后的模型系数(θ1, θ2, ..., θn)。如果是多重线性回归,返回的是一个一维数组,表示每个特征的权重。
intercept_:拟合后的截距(θ0)。
n_iter_:模型训练过程中的迭代次数(仅在使用某些优化方法时可用)。
rank_:矩阵 X 的秩。
singular_:X 的奇异值。
3、线性回归问题求解
线性回归问题的求解方式是最小化损失函数,有两种方式:
- 一种是上方代码所示,直接 fit 给模型所有的数据,然后会直接计算出最终的 w , b w,b w,b,它是一种暴力求解的方式,所做的是对每一个参数求偏导,以
导数为零就是极值,带入全部的特征向量X,目标值Y解出最优参数值。 - 另一种是常用的梯度下降法。沿着梯度下降的方向求解极小值。
损失函数:
线性回归常用的损失函数是:LS最小二乘法、MSE均方误差 、MAE平均绝对误差。
- LS使用的是误差平方和的方式:

其中, y i y_i yi是第i个数据点的真实值,
是第 i 个数据点的预测值。
- MSE使用的是误差平方和取平均值:

其中:n 是样本数量, y i y_i yi是第 i 个数据点的真实值,
是第 i 个数据点的预测值。
- MAE:使用的是误差绝对值和取平均值

其中:n 是样本数量, y i y_i yi是第 i 个数据点的真实值。
前面已经说过,我们求解线性回归问题就是要最小化损失,也就是说我们要让模型的预测值尽可能的接近真实值。上面提到的直接暴力带入求解方法,在数据量庞大的情况下很有可能陷入无法求解的状态,并且计算量庞大。接下来介绍一种非常普遍的做法:梯度下降法。
梯度下降:
先给出通俗解释:梯度下降的方向就是极值点所在位置,即我们要求的解。
梯度下降所采用的思想是求梯度,即函数中的求导(多元中是求偏导),而一元函数在某一点导数是代表了该点的斜率的,它的正数是代表了该点邻域内函数是增长,负数代表了该点邻域内函数减小,对于正梯度是正数,负梯度是负数,梯度的反方向就是负的梯度。对于多元函数,梯度的正方向是函数增长最快的方向,负梯度是函数下降最快的方向。而两者往梯度的负方向走都是求解极值。
假设有下边这样一个一元函数 y = f ( x ) y=f(x) y=f(x),它的函数图像如下:

目标是找到能让 f ( x ) f(x) f(x)最小的首先随机设置 x x x的初始值,比如点 x 0 = 4 x_0=4 x0=4;

求出导数,画出代表该点斜率的直线,我们可看到该点导数是大于 0 的,根据上面的定义,导数大于 0 ,表示在该点 x x x向右变化时,函数 f ( x ) f(x) f(x)是增大的,向左变化时函数是减小的。
所以由导数的正负号我们就能够确定 x x x的移动方向,也就是导数的负方向,如果导数为正就对 x x x取左邻域的值,如果导数为负,那意味着对 x x x取右邻域的值,这样我们就能获得更小的 f ( x ) f(x) f(x) 值,反映在线性回归问题求解上也即找到了相比上一次更加优异的一个解(这个解其实就是线性回归模型的权重 w w w 和偏置 b b b )。
对于多元的情况,其实是一个道理,只不过当特征为多维的时候我们需要的是对每个特征权重求偏导,令所有的偏导结果为 0 ,解出的答案也就是函数的最优解。

讲了梯度下降 和 损失函数的概念,那么这里可以给出梯度下降求解法的思想就是:让损失函数最小,损失函数求最小值的方法就是梯度下降法。
当然这里还涉及到局部极值和全局极值的情况,这一部分在这里不做赘述,感兴趣的可以另外了解。
梯度下降公式:

其中 θ θ θ,是参数, i , i + 1 i,i+1 i,i+1表示第几轮的参数值, α α α是后面要解释的学习率, J ( θ ) J(θ) J(θ)是目标函数,或称为损失函数。
学习率:
前面了解到求解线性回归问题的方法是向着梯度下降的方向寻找最优解,那么这里思考一个问题,搜寻具体要按照什么步长前进呢?会不会在即将求到极值的时候不小心越过了这个极值?或者在极值点来回震荡?
其实可以直接以导数值作为步长,这样随着越接近极值点,导数值会越来越趋近于 0 ,曲线也变的平缓,导数值变小,每次步长也变小,这有利于我们在全局最低点附近进行精细调整,最终到达全局最低点。
看起来该方法似乎不错,但其实还需要乘上一个系数,称为步长系数,也可以叫它常用的称呼:学习率 ( Learning Rate ), 简写lr。因为导数值并不是总是那么合适,有时候偏大,导致步长太大,跳过全局最小值。有时候偏小,导致训练过程很慢。这时就可以通过设置学习率来调整。一般情况下,学习率都是小于1的。比如设置为0.001。

参数和超参数:
参数:在机器学习领域,在训练过程中由算法调整的变量叫做参数。参数是通过数据学习而来的,不是人为设定的。参数决定了模型如何从输入数据映射到输出。训练好的模型会保存这些参数,以便在预测/推理时使用。比如线性回归里的权重和偏置就是参数。
超参数是模型训练前需要人为设置的变量,它们不会在训练过程中自动学习,而是由人根据实验或者经验设定的。比如学习率就是一个超参数。
4、常见的梯度下降方法
前面了解到了求解线性回归问题的一个有效方法------梯度下降法,接下来介绍几种常见的梯度下降方法。
全梯度下降算法FGD(Full Gradient Descent)
每次迭代时, 使用全部样本的梯度值,由于使用全部数据集,训练速度较慢。
随机梯度下降算法 SGD
每次迭代时, 随机选择并使用一个样本梯度值 ,简单高效不稳定,容易陷入局部最优解。
API:
python
from sklearn.linear_model import SGDRegressor(loss="squared_loss", fit_intercept=True, learning_rate ='constant', eta0=0.01)
小批量梯度下降算法 mini-batch
每次迭代时, 随机选择并使用小批量的样本梯度值,从m个样本中,选择x个样本进行迭代(1<x<m),避开了 FG 运算效率低成本大和 SG 收敛效果不稳定的缺点。
随机平均梯度下降算法 SAG
每次迭代时, 随机选择一个样本的梯度值和以往样本的梯度值的均值,训练初期表现不佳,优化速度较慢。
5、回归模型的评估方法
回归模型的评估方法主要有以下几种,注意与分类模型相区分!
平均绝对误差 Mean Absolute Error (MAE)
i i i代表当前第几个标签, y y y表示真实标签值, y ^ \hat y y^表示预测值。
API:
python
from sklearn.metrics import mean_absolute_error
mean_absolute_error(y_test,y_predict)
MAE 越小模型预测约准确,MAE对误差大小不敏感
均方误差 Mean Squared Error (MSE)
i i i代表当前第几个标签, y y y表示真实标签值, y ^ \hat y y^表示预测值。
API:
python
from sklearn.metrics import mean_squared_error
mean_squared_error(y_test,y_predict)
MSE 越小模型预测约准确
均方根误差 Root Mean Squared Error (RMSE)
i i i代表当前第几个标签, y y y表示真实标签值, y ^ \hat y y^表示预测值。
用法:
python
from sklearn.metrics import mean_squared_error
import numpy as np
np.sqrt(mean_squared_error(y_test,y_predict))
RMSE 越小模型预测约准确,RMSE 是 MSE 的平方根
大多数情况下RMSE>MAE,RMSE 会放大预测误差较大的样本对结果的影响,对异常点更加敏感,而 MAE 只是给出了平均误,通过两者之间的差值可以判断出数据是否均匀。
6、模型的欠拟合、过拟合
-
欠拟合
模型在训练集上表现不好,在测试集上也表现不好。模型过于简单
原因:学习到数据的特征过少
解决方法:添加其他特征、添加多项式特征
-
过拟合
模型在训练集上表现好,在测试集上表现不好。模型过于复杂
原因:原始特征过多,存在一些嘈杂特征, 模型过于复杂是因为模型尝试去兼顾各个测试数据点
解决方法:重新清洗数据;增大数据的训练量;正则化;减少特征维度,防止维灾难
7、正则化
在模型训练时,数据中有些特征影响模型复杂度、或者某个特征的异常值较多, 所以要尽量减少这个特征的影响(甚至删除某个特征的影响),这就是正则化。解决过拟合 的方法是在函数中增加正则化项。
- L1正则化:
在损失函数中添加L1正则化项:

α 叫做惩罚系数,该值越大则权重调整的幅度就越大;L1 正则化会使得权重趋向于 0,甚至等于 0,使得某些特征失效,达到特征筛选的目的。
使用 L1 正则化的线性回归模型是 Lasso 回归。
Lasso回归API:
python
from sklearn.linear_model import Lasso
参数
alpha:正则化强度,控制模型中参数的惩罚程度。较大的 alpha 会导致更强的正则化,更多的系数变为零。alpha=0 时,Lasso 就退化为普通的线性回归。
fit_intercept:是否计算截距项,默认为 True,即包含截距项。
max_iter:最大迭代次数,默认为 1000,如果数据量较大或收敛较慢,可以增加该值。
tol:求解器的容忍度,默认为 1e-4,用于控制收敛的精度。
- L2正则化:

α 叫做惩罚系数,该值越大则权重调整的幅度就越大;L2 正则化会使得权重趋向于 0,一般不等于 0。
使用 L2 正则化的线性回归模型是岭回归。
岭回归的API:
python
from sklearn.linear_model import Ridge
参数
alpha:正则化强度,控制模型中参数的惩罚程度。与 Lasso 类似,较大的 alpha 会导致更强的正则化,系数变得更小。alpha=0 时,Ridge 就退化为普通的线性回归。
fit_intercept:是否计算截距项,默认为 True。
max_iter:最大迭代次数,默认为 1000,当数据集较大时可以增加该值。
tol:求解器的容忍度,默认为 1e-4,用于控制收敛的精度。
波士顿房价预测案例:
python
# from sklearn.datasets import load_boston
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression, SGDRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]
# print(data,'\n', target)
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=0)
# 标准化
ssm = StandardScaler()
new_x_train = ssm.fit_transform(x_train)
new_x_test = ssm.transform(x_test)
# 模型训练
line_model = LinearRegression(fit_intercept=True)
line_model.fit(new_x_train, y_train)
sgd_model = SGDRegressor(fit_intercept=True, loss='squared_error', learning_rate='adaptive', eta0=0.25)
sgd_model.fit(new_x_train, y_train)
y_pred = line_model.predict(new_x_test)
y_pred2 = sgd_model.predict(new_x_test)
print(f'最优w:{line_model.coef_}')
print(f'最优b:{line_model.intercept_}')
print(mean_absolute_error(y_test, y_pred))
print(mean_squared_error(y_test, y_pred))
print(np.sqrt(mean_squared_error(y_test, y_pred)))
print('----------------------------------')
print(f'最优w:{sgd_model.coef_}')
print(f'最优b:{sgd_model.intercept_}')
print(mean_absolute_error(y_test, y_pred2))
print(mean_squared_error(y_test, y_pred2))
print(np.sqrt(mean_squared_error(y_test, y_pred2)))






