前言:
线性回归在统计学中占据着极其重要的地位,可以说很多算法都是依据线性回归而优化升级出来的。因此,了解线性回归的基本原理,是学习统计学、机器学习不可或缺的一步。
关键词:一元线性回归、多元线性回归、最小二乘法、矩阵求导
引入:
严谨的一对一,一对多的数学函数往往具有更大的说服力。然而,在日常的生活中,我们不得不承认,这种带有估计量的统计学更切近日常。因为生活中我们往往没有办法能够拿到所有的数据,因此,退而求其次地取其样本来估计总体就成了统计学的目标。而线性回归,就便是用样本来估计总体的一个算法。比如在研究国民体重和身高的关系的时候,我们没有办法对所有人都进行丈量,因此我们希望从人群中抽样出一部分具有代表性的人,对他们进行衡量,从而建立一个数学模型。估计出大概的身高和体重的关系。
算法原理及其推导:
高中数学就已经教过线性回归的内容。其图像表达如下:
我们的目标就是用样本去拟合一条直线y=wx+b。其中y为对应的函数值,w被称为权重值或者参数,b为截距项也同时称为参数。我们可以将x看作是体重,y看作是身高,我们的目标就是要找出他们的关系。具体步骤可分为4步,也是统计机器学习几乎都要经历的4步:
- 选定模型算法。
- 确定损失函数。
- 估计模型参数。
- 用模型去估计预测。
那么什么是损失函数,简而言之就是损失函数就是预测的值和真实值的差值
其中y为对应的样本真实值,为对应的y=wx+b的值。我们的目标显而易见,就是要让
最小,因此,损失函数的就可以写成如下
再严谨一些实际上应该写作:
意为将w、b作为变量,最小化这个函数。
因此,当我们找到能够使这个函数达到最小,对应的w,b就是我们所要求的参数。那么如何能够求到最小值,当燃是使用最小二乘法啦,依据最小二乘法。我们可以得出如下公式(此处以一维变量为例,即假设x的维度是一维)
一元线性回归推导:
即当w、b的取值为上面的值的时候,我们就认为此时的损失函数达到最小。其中为单个样本其公式推导如下:
因为我们要最小化公式(1.3).因此,根据我们的常识,如何求一个函数的最小值呢?当然是导数啦!公式中将W,b作为变量,因此,我们对这两个变量分别求导:
对b求导(以下为了方便对Σ的起止省略):
因为b的值不受i控制,因此
所以:
移项得:
对w求导并等于0:
将式(1.5)代入:
移项得:
即:
因为:
所以:
因此,公式就出来啦!
多元线性回归推导:
然而,现实生活中,我们遇到的往往不仅仅是体重和身高关系的这种问题,其有更为复杂的问题。比如我们要研究一个人的(身高,体重,颜值,智商)等等与气质的关系。并且要求求出各个变量对气质的影响程度,因此。我们就要引入多元线性回归。其表达式我们依然用
注意了,这里的W^1代表的是W的分量的,也就是W的一个维度分量。
为了方便运算和求导证明,接下来我们对线性方程变换一下y=w^T*X
其中:
那么此时的损失函数又该如何求解呢?首先,必须掌握对矩阵求导的知识。
在此笔者不作证明,直接给出必要的矩阵求导公式,感兴趣的读者可以查阅资料进行了解。
来看损失函数,
令:
令
由此可得:
所以:“
由于:
因此
要对其求最小化,就对其W求导:
整理得:
优化:
可以看到,公式(1.7)实际上是有点问题的,我们如何确定一定可逆呢?我们是无法确定的,当样本的容量不能够远远的大于样本的维度时,可能会造成
不可逆。换一角度来说,这实际上会造成模型的过拟合。而解决模型过拟合的方式,有一种·有力的方式就是在损失函数加入L1或者L2正则化项。最终其损失函数如下
最终沿用上面的求解方法,得出:
因为
。
所以为半正定矩阵,又因λI
为正定矩阵,所以
为正定矩阵,可逆。
代码实现:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from mpl_toolkits.mplot3d import Axes3D
'''
本次代码使用二维变量
'''
np.random.seed(200) #随机数种子
#绘图函数
def plt_piture(x1,x2,norm_y,w):
fig=plt.figure()
y_predict=x1*w[0][0]+x2*w[1][0]+w[2][0]
ax=Axes3D(fig)
ax.plot(x1,x2,y_predict)
ax.scatter(x1,x2,norm_y, c="r")
plt.show()
def main():
x1 = np.arange(0, 100, 2).reshape(-1,1)#变量的第一个维度并重新定义形状
x2=np.arange(0,100,2).reshape(-1,1)#变量的第二个维度并重新定义形状
x=np.concatenate([x1,x2],axis=1)#将两个维度合并 shape(50,2)
#依据公式,为了方便,我们将x的维度扩展一个全为1的维度
x_b=np.concatenate([x,np.ones_like(x1).reshape(-1,1)],axis=1)
#计算对应的y,并从均值为0,方差为10的正太分布中抽取样本加上原始的y值
norm_y=(x1+x2+stats.norm.rvs(0,10,x1.size).reshape(-1,1))
#依据普通损失函数,利用最小二乘法求出w的值,其中@代表点积,pinv求矩阵的伪逆
w=np.linalg.pinv(x_b.T@x_b)@x_b.T@norm_y
#计算正则化后的损失函数对应的w,linalg.inv为求矩阵的逆,np.eye是生成单位矩阵
lambda_=0.01
norm_w=np.linalg.inv(x_b.T@x_b+lambda_*np.eye(x_b.shape[1]))@x_b.T@norm_y
#打印对应的值
print("原损失函数的权重值:")
print("x1系数为{}".format(w[0][0]))
print("x2系数为{}".format(w[1][0]))
print("截距b为{}".format(w[2][0]))
print("正则化后损失函数的权重值:")
print("x1系数为{}".format(norm_w[0][0]))
print("x2系数为{}".format(norm_w[1][0]))
print("截距b为{}".format(norm_w[2][0]))
#绘制函数图像
plt_piture(x_b[:,0],x_b[:,1],norm_y.reshape(-1),w)
if __name__ == '__main__':
main()
结束语:
文章中有许多不够严谨的地方,如果有什么不对的地方还望读者能够不吝赐教。因为笔者也是正在学习的阶段,写博客纯粹就是为了确认自己是否是真的懂了,是否遗漏了什么细节,是否印象足够深刻。所以,各位多多担待哈,阿里嘎多。