首先做一道高中数学题 下表提供了某厂节能降耗技术改造后产生甲产品过程中记录的产量x(单位:吨)与相应的生产能耗y(单位:吨/标准煤)的几组对照数据。
【解】(1)散点图如下: (2)根据题中所给数据,可得: ∴所求线性回归方程为 (3)根据(2)求出的线性回归方程及题干,得降低的生产能耗为: y=90-0.7×100+0.35=19.65(吨/标准煤) |
上面这道高考题所考察的知识就是最基本的线性回归。我记得中学阶段求解回归方程的重要公式:
中学阶段我们已经知道线性回归就是利用已知数据(根据上述公式)求得回归方程,通过回归方程预测未知数据。上面这道题的回归方程图像下:
事实上,这道题中所涉及的回归问题正是输入数据只有一个属性(即样本的类型只有一种,换句话说,仅通过一类样本——如题中的产量,来预测结果——如题中的生产能耗)的线性回归问题。首先从单属性回归任务入手:
假设输入数据样本D={(x1, y1), … , (xm, ym)},线性回归通过建立线性模型
预测真实标记yi。要得到线性回归模型,就是要求参数a和b。均方误差是回归任务中最常用的性能度量,因此这里选择让均方误差最小化:
此时求出的a*、b*即为最优参数。
要求解上面这个式子,可通过分别对两参数求导来求解。设 ,则分别对a、b求偏导并令为0得:
解得:
对上式化简,就可得到前文所述中学阶段求解回归方程的重要公式 |
线性回归的一般形式
至此,最简单的线性回归模型基本理解得差不多了,接下来就是要将 “特殊”推广为“一般”了。首先将数据样本D一般化为数据集D={(x1, y1), … , (xm, ym)},其中xi=(xi1, xi2,…, xid)T,即样本有d个属性(就好比开头那道题中,原来样本只有产量这一属性来预测生产能耗,现在增加了温度和设备损耗度两个属性来共同预测生产能耗,可表示为:生产能耗=F(产量, 温度, 损耗度))。此时一般化的线性回归模型(也称“多元线性回归”)表示如下:
为方便表示,即令,令 ,则线性回归一般化表示为:
同理,通过均方误差最小化求最优参数解。均方误差如下:
为什么选用均方误差作为性能度量? |
上面我们得到了回归函数的一般形式: 回归函数是我们通过已知数据建立的模型,与真实情况肯定存在误差。误差ε可以表示为: 这些误差将会形成一个分布,我们一般认为误差是随机的,是由众多因素造成的,并且是相互独立的,根据中心极限定理,这些误差服从正态分布,其概率密度函数如下: 然后建立关于无数样本(假设为上述数据集的样本个数m个)的联合概率密度函数: 显然,这就是似然函数,对其取对数得: 可以看出,要使似然函数最大化,就是要最小化 ,即最小化均方误差。 |
损失函数、代价函数、目标函数
损失函数是用来度量单个样本预测的错误程度的。线性回归说白了就是找一条最符合样本集的直线,这条直线所预测的结果和每个样本的真实结果肯定会有偏差,这个偏差其实就是前面所说的那个误差ε。
一般我们只关注这个偏差或误差的量的大小,而不关注它的正负,因此我们对偏差ε取绝对值|ε|,这样便得到了绝对值损失函数 |ε|=|f(x)-y|。
但是根据前文我们通过最小二乘法来求得最优模型,其中会经历求导的过程,而|ε|可能并不光滑,可能会求导不便,此时可取其平方|ε|^2=(f(x)-y)^2,这样既不改变函数性质,计算也相对更简便,因此我们更倾向选择|ε|^2作为损失函数。这就是平方损失函数。同时我们也可看出,损失函数值越小,模型就越好。
代价函数是度量全部样本集的平均误差的。很明显,前文提到了通过均方误差最小化求最优参数解,均方误差就是线性回归中最常用的代价函数,它其实就是说明了直线上点到真实数据点的距离之和。
线性回归的目标函数是最优化经验风险和结构风险的优化函数,一般是代价函数+正则化项。因此,线性回归的目标函数可表示为:
其中,J(F)为模型复杂度。目标函数增加了优化结构风险,主要是为了防止过拟合。
优化方法
到这里终于要开始求解模型了。线性回归模型可通过以下几种优化方法进行优化建立。
- 梯度下降法
将代价函数想象成一个山谷,通过在所在位置,寻找下山最快的方向,这个方向就是函数梯度的反方向。假设步长为α,梯度下降法通过朝梯度反方向每次下降步长为α的距离,最终到达谷底,即函数的最小值点,实现模型的优化。梯度下降的算法为:
上式可以如下简化:
梯度下降有个缺点,即函数是非凸函数时,可能陷入局部最小值。此时可以改进为随机梯度下降或小批量梯度下降。
- 最小二乘法
对应单变量线性回归的最小二乘法优化过程,一般化的线性回归的最小二乘法优化模型可如下表示:
令 , ,
代价函数E可表示为:
对θ求导可得:
令 ,则:
这个方法也叫做正规方程法,对于有些线性回归问题,这个方法会更好。但当矩阵不可逆(通常是因为属性之间不独立,或属性数量大于训练集的数量)时,此方法不可用。
- 牛顿法
牛顿法的原理如下:
正如上图所示,对于方程f(x)=0,取函数f(x)上一点x0,在(x0, f(x0))处做切线,再取切线与x轴的交点的横坐标x1,再在(x1, f(x1))处做切线,交x轴于x2,如此往复循环,最终在xn处到达函数f(x)的最小值处。牛顿法的几何意义明显,因此也叫切线法。牛顿法的迭代内容可表示为:
多维时牛顿法的迭代公式为:
其中,H为海森矩阵。
- 拟牛顿法
由于海森矩阵的计算较为复杂,因此就出现了拟牛顿法:用一个正定矩阵代替海森矩阵的逆矩阵,减少运算复杂度。
(牛顿法和拟牛顿法不太明白,准备再学学,单独做一篇笔记)
评价指标
均方误差(MSE):
均方根误差(RMSE):
平均绝对误差(MAE):
以上评价指标都无法消除量纲不一致而导致的误差值差别大的问题,最常用的指标是R^2,可以避免量纲不一致问题:
R^2可以理解为:回归模型可以成功解释的数据方差部分在数据固有方差中所占的比例,R^2越接近1,表示可解释力度越大,模型拟合的效果越好。
python实现
#生成数据
import numpy as np
#生成随机数
np.random.seed(1234)
x = np.random.rand(500,3)
#构建映射关系,模拟真实的数据待预测值,映射关系为y = 4.2 + 5.7*x1 + 10.8*x2,可自行设置值进行尝试
y = x.dot(np.array([4.2,5.7,10.8]))
梯度下降法:
#gradient descent
class LR_GD():
def __init__(self):
self.w = None
def fit(self,X,y,alpha=0.02,loss = 1e-10): # 设定步长为0.002,判断是否收敛的条件为1e-10
y = y.reshape(-1,1) #重塑y值的维度以便矩阵运算
[m,d] = np.shape(X) #自变量的维度 (m为样本数,d为属性个数)
self.w = np.ones((d,1)) #将参数的初始值定为0
tol = 1e5
#============================= show me your code =======================
i = 0
while tol > loss:
# here
j = (2 / m) * X.T.dot((X.dot(self.w) - y)) # 代价函数梯度
self.w -= alpha * j # 梯度下降迭代
tol = np.sum(np.square(X.dot(self.w) - y)) / m # 误差
i += 1 # 迭代次数
print("训练轮数:",i,"误差:",tol,"参数:",self.w)
print('*********训练结束**********')
#============================= show me your code =======================
def predict(self, X):
# 用已经拟合的参数值预测新自变量
y_pred = X.dot(self.w)
return y_pred
if __name__ == "__main__":
lr_gd = LR_GD()
lr_gd.fit(x,y)
print("估计的参数值为:%s" %(lr_gd.w))
x_test = np.array([2,4,5]).reshape(1,-1)
print("预测值为:%s" %(lr_gd.predict(x_test)))
最小二乘法:
class LR_LS():
def __init__(self):
self.w = None
def fit(self, X, y):
# 最小二乘法矩阵求解
#============================= show me your code =======================
self.w = np.linalg.inv(X.transpose().dot(X)).dot(X.transpose()).dot(y)
#============================= show me your code =======================
def predict(self, X):
# 用已经拟合的参数值预测新自变量
#============================= show me your code =======================
y_pred = X.dot(self.w)
#============================= show me your code =======================
return y_pred
if __name__ == "__main__":
lr_ls = LR_LS()
lr_ls.fit(x,y)
print("估计的参数值:%s" %(lr_ls.w))
x_test = np.array([2,4,5]).reshape(1,-1)
print("预测值为: %s" %(lr_ls.predict(x_test)))
参考资料
- 线性回归(百度百科)https://baike.baidu.com/item/%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/8190345?fr=aladdin
- 通俗理解线性回归(一)https://blog.csdn.net/alw_123/article/details/82193535
- 回归(一):线性回归https://www.jianshu.com/p/3a98f33113ac
- 如何理解最小二乘法?https://blog.csdn.net/ccnt_2012/article/details/81127117
- 深入理解机器学习中的:目标函数,损失函数和代价函数https://blog.csdn.net/qq_28448117/article/details/79199835
- 机器学习中的目标函数、损失函数、代价函数有什么区别?https://www.zhihu.com/question/52398145
- 海森矩阵及其应用https://blog.csdn.net/hellocsz/article/details/88864289
- 【傻瓜攻略】深度学习之海森矩阵(九)https://blog.csdn.net/lyy_sha/article/details/80594931
- Jacobian矩阵和Hessian矩阵https://www.cnblogs.com/wangyarui/p/6407604.html
- 《统计学习方法》.李航
- 《深度学习》(花书)
- 《机器学习》(西瓜书)