在 机器学习模型中,线性模型是一种形式简单但包含机器学习主要建模思想 的模型 ,线型模型包含线性回归、对数几率回归、LASSO回归、RIDGE回归、lLDA等模型。线性回归是一种由自变量到因变量的机器学习建模思想。
一、一元回归最小二乘法推导
给定一组由输入X和输出 Y构成的数据集
D={(x1,y1),(x2,y2)....(xm,ym)}
其中 x={x1,x2,....}, y属于R,线性回归就是通过训练学习得到一个线性模型。模型为:
y=wx+b
线性回归学习的关键问题在确定参数w和b,使得拟合输出 的y 与真实输出 的y尽可能接近。在回归任务中,我们通常使用均方误差度量预测与标签之间的损失,回归任务的优化目标就是使拟合输出和真实输出的均方差最小化,所以有:
为求w和b的最小化参数w*和b*, 可基于式2-1分别对w和b求一阶导数并令其为0,对w求导的推导过程如式2-2所示:
同理,对参数b求导的推导过程 如式2-3所示:
基于式2-2和式2-3,分别令其为0,可解得w和b 的最优解
这是一种基于均方差最小化求解线性回归参数的方法就是著名的最小二乘法,其图示如下所示:
二、多元回归推导
所谓多元回归,就是输入多个变量X,输出 变量Y,为了方便矩阵化的最小二乘法的推导 ,可将w和b合并向量表达式w=(w,b),训练集D的输入部分可表示为一个mx(d+1)维的矩阵X,其中d为输入变量的个数,则矩阵X可表示为:
输出Y的向量表达形式为 ,参数优化目标函数的矩阵化表达式为:
基于2-7对参数w求导,其推导过程如下:
根据矩阵微分公式:
可得:
当矩阵为XTX满秩矩阵或者正定矩阵时,令2-13等于0,可解得参数为:
有时矩阵并不是满秩矩阵,通过对XTX添加正则化项使该矩阵可逆,典型表达式如下:
在线性回归模型的迭代训练时,通常使用梯度下降 之类的优化算法求得w 的最优估计 。
线性回归蕴含了机器学习思想,即对于任何目标变量y,我们总能基于一系列输入变量X,根据目标变量的类型,分别构建回归和分类模型。
三、代码实现
使用Numpy实现一个线性回归模型,按照机器 学习三要素(模型、策略、算法 )的原则,逐步搭建线性回归代码框架 。
1、编写思路
在具体编写过程中,基于均方损失最小化的优化策略和梯度下降 的寻优算法非常关键,一个线性回归模型代码的编写思路如下所示:
2、回归模型主体
线性回归模型的主体部分,包括 回归模型公式 】均方损失函数和参数求领导,其实现代码 如下所示:
# 导入numpy模块
import numpy as np
### 定义模型主体部分
### 包括线性回归模型公式、均方损失函数和参数求偏导三部分
def linear_loss(X, y, w, b):
'''
输入:
X:输入变量矩阵
y:输出标签向量
w:变量参数权重矩阵
b:偏置
输出:
y_hat:线性回归模型预测值
loss:均方损失
dw:权重系数一阶偏导
db:偏置一阶偏导
'''
# 训练样本量
num_train = X.shape[0]
# 训练特征数
num_feature = X.shape[1]
# 线性回归预测值
y_hat = np.dot(X, w) + b
# 计算预测值与实际标签之间的均方损失
loss = np.sum((y_hat-y)**2) / num_train
# 基于均方损失对权重系数的一阶梯度
dw = np.dot(X.T, (y_hat-y)) / num_train
# 基于均方损失对偏置的一阶梯度
db = np.sum((y_hat-y)) / num_train
return y_hat, loss, dw, db
3、初始化模型参数
初始化模型参数,主要有输入训练数据的变量维度,零向量和零偏置,代码如下:
### 初始化模型参数
def initialize_params(dims):
'''
输入:
dims:训练数据的变量维度
输出:
w:初始化权重系数
b:初始化偏置参数
'''
# 初始化权重系数为零向量
w = np.zeros((dims, 1))
# 初始化偏置参数为零
b = 0
return w, b
4、定义训练过程
在定义训练过程中,首先初始化模型参数,然后对遍历设置训练迭代过程,在每次迭代过程中,计算当前迭代的预测值,均方损失和梯度,并根据 梯度下降法不断更新系数,记录每一步损失,保存更新后的模型参数字典和梯度字典。代码如下所示:
### 定义线性回归模型的训练过程
def linear_train(X, y, learning_rate=0.01, epochs=10000):
'''
输入:
X:输入变量矩阵
y:输出标签向量
learning_rate:学习率
epochs:训练迭代次数
输出:
loss_his:每次迭代的均方损失
params:优化后的参数字典
grads:优化后的参数梯度字典
'''
# 记录训练损失的空列表
loss_his = []
# 初始化模型参数
w, b = initialize_params(X.shape[1])
# 迭代训练
for i in range(1, epochs):
# 计算当前迭代的预测值、均方损失和梯度
y_hat, loss, dw, db = linear_loss(X, y, w, b)
# 基于梯度下降法的参数更新
w += -learning_rate * dw
b += -learning_rate * db
# 记录当前迭代的损失
loss_his.append(loss)
# 每10000次迭代打印当前损失信息
if i % 10000 == 0:
print('epoch %d loss %f' % (i, loss))
# 将当前迭代步优化后的参数保存到字典中
params = {
'w': w,
'b': b
}
# 将当前迭代步的梯度保存到字典中
grads = {
'dw': dw,
'db': db
}
return loss_his, params, grads
5、导入数据集
在此实例中,使用sklearn的dieabets数据集进行测试,导入数据集并将其划分为训练集和测试集,代码如下所示:
# 导入load_diabetes模块
from sklearn.datasets import load_diabetes
# 导入打乱数据函数
from sklearn.utils import shuffle
# 获取diabetes数据集
diabetes = load_diabetes()
# 获取输入和标签
data, target = diabetes.data, diabetes.target
# 打乱数据集
X, y = shuffle(data, target, random_state=13)
# 按照8∶2划分训练集和测试集
offset = int(X.shape[0] * 0.8)
# 训练集
X_train, y_train = X[:offset], y[:offset]
# 测试集
X_test, y_test = X[offset:], y[offset:]
# 将训练集改为列向量的形式
y_train = y_train.reshape((-1,1))
# 将测试集改为列向量的形式
y_test = y_test.reshape((-1,1))
# 打印训练集和测试集的维度
print("X_train's shape: ", X_train.shape)
print("X_test's shape: ", X_test.shape)
print("y_train's shape: ", y_train.shape)
print("y_test's shape: ", y_test.shape)
6、模型训练过程
代码 如下:
# 线性回归模型训练
loss_his, params, grads = linear_train(X_train, y_train, 0.01, 200000)
# 打印训练后得到的模型参数
print(params)
输出如下:
QQQ:
{'w': array([[ 10.56390075],
[-236.41625133],
[ 481.50915635],
[ 294.47043558],
[ -60.99362023],
[-110.54181897],
[-206.44046579],
[ 163.23511378],
[ 409.28971463],
[ 65.73254667]]),
'b': 150.8144748910088}
均方损失下降过程图:
7、回归模型的预测函数
定义一个预测函数对测试集进行预测,代码 如下:
### 定义线性回归模型的预测函数
def predict(X, params):
'''
输入:
X:测试集
params:模型训练参数
输出:
y_pred:模型预测结果
'''
# 获取模型参数
w = params['w']
b = params['b']
# 预测
y_pred = np.dot(X, w) + b
return y_pred
# 基于测试集的预测
y_pred = predict(X_test, params)
8、回归模型R2系数
评估模型预测结果好坏一个重要指标为R2系数,以下代码定义了其计算方式。
### 定义R2系数函数
def r2_score(y_test, y_pred):
'''
输入:
y_test:测试集标签值
y_pred:测试集预测值
输出:
r2:R2系数
'''
# 测试集标签均值
y_avg = np.mean(y_test)
# 总离差平方和
ss_tot = np.sum((y_test - y_avg)**2)
# 残差平方和
ss_res = np.sum((y_test - y_pred)**2)
# R2计算
r2 = 1- (ss_res/ss_tot)
return r2
# 计算测试集的R2系数
print(r2_score(y_test, y_pred))
输出如下:0.5334188457463576
9、基于sklearn模型的实现
以下是基于LinearRegression类的模型拟合和预测代码:
# 导入线性回归模块
from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score
# 定义模型实例
regr = linear_model.LinearRegression()
# 模型拟合训练数据
regr.fit(X_train, y_train)
# 模型预测值
y_pred = regr.predict(X_test)
# 输出模型均方误差
print("Mean squared error: %.2f"% mean_squared_error(y_test, y_pred))
# 计算R2系数
print('R Square score: %.2f' % r2_score(y_test, y_pred))
输出如下:
输出如下:
Mean squared error: 3371.88
R Square score: 0.54
线性回归包含了最朴素的由自变量到因变量的机器学习建模思想。基于均方误差最小化的最小二乘法是线性回归模型求解的基本方法,通过最小均方误差和R2系数可以评估线性回归的拟合效果。