线性回归原理分析

1 回归问题定义

线性回归是利用数理统计中回归分析,来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。
回归分析中,只包括一个自变量和一个因变量,且二者的关系可用一条直线近似表示,这种回归分析称为一元线性回归分析。 如果回归分析中包括两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析

回归问题的一般表达式为
(1.1) f ( x ) = θ 1 x 1 + θ 2 x 2 + . . . + θ d x d + b f(x) = \theta_1x_1 + \theta_2x_2 + ...+ \theta_dx_d + b \tag{1.1} f(x)=θ1x1+θ2x2+...+θdxd+b(1.1)
用向量形式写作
(1.2) f ( x ) = θ T x + b f(x) = \theta^Tx + b\tag{1.2} f(x)=θTx+b(1.2)
其中θ =(θ 12;…;θ d),θ 与b确定后,这个线性模型就得以确定,我们则通过这个模型来预测数据,所以我们的目的就是去修改θ 和b的值,好让模型的预测值尽可能的与真实值一样。

2 问题求解

2.1目标函数引出

假设我们有m个样本,对于每个样本我们的预测值与误差的关系为
(2.1) y ( i ) = θ T x ( i ) + ϵ ( i ) y^{(i)} = \theta^Tx^{(i)} + \epsilon^{(i)} \tag{2.1} y(i)=θTx(i)+ϵ(i)(2.1)
其中 ϵ 为误差值,该误差 ϵ (i)是独立并且具有相同的分布,且服从均值为0方差为θ2的高斯分布,所以有
(2.2) p ( ϵ ( i ) ) = 1 2 π δ e x p ( − ( ϵ ( i ) ) 2 2 δ 2 ) p(\epsilon^{(i)}) = \frac{1}{\sqrt{2\pi}\delta}exp\left(-\frac{(\epsilon^{(i)})^2}{2\delta^2}\right)\tag{2.2} p(ϵ(i))=2π δ1exp(2δ2(ϵ(i))2)(2.2)
将式2.1代入式2.2即有
(2.3) p ( y ( i ) ∣ x ( i ) ; θ ) = 1 2 π δ e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 δ 2 ) p(y^{(i)}|x^{(i)};\theta) = \frac{1}{\sqrt{2\pi}\delta}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\delta^2}\right)\tag{2.3} p(y(i)x(i);θ)=2π δ1exp(2δ2(y(i)θTx(i))2)(2.3)
于是得到似然函数
(2.4) L ( θ ) = ∏ i = 1 m 1 2 π δ e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 δ 2 ) L(\theta) = \prod_{i=1}^m\frac{1}{\sqrt{2\pi}\delta}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\delta^2}\right)\tag{2.4} L(θ)=i=1m2π δ1exp(2δ2(y(i)θTx(i))2)(2.4)
似然函数的意思就是我们取什么样的参数和我们的数据组合后恰好为真实值,为了让真实值和我们模型的预测值之间的误差最小,因此我们要让L(θ)最大。接下来对L(θ)表达式进行化简。为了方便计算,先对式2.4两边取log。
(2.5) l o g L ( θ ) = ∑ i = 1 m l o g 1 2 π δ e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 δ 2 ) = m l o g 1 2 π δ − 1 2 ∑ i = 1 m ( y ( i ) − θ T x ( i ) ) 2 \begin{aligned} logL(\theta) &= \sum_{i=1}^m log\frac{1}{\sqrt{2\pi}\delta}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\delta^2}\right)\\ &=mlog\frac{1}{\sqrt{2\pi}\delta} - \frac{1}{2}\sum_{i=1}^m(y^{(i)}-\theta^Tx{(i)})^2\\ \tag{2.5} \end{aligned} logL(θ)=i=1mlog2π δ1exp(2δ2(y(i)θTx(i))2)=mlog2π δ121i=1m(y(i)θTx(i))2(2.5)

(2.6) 令 J ( θ ) = 1 2 ∑ i = 1 m ( y ( i ) − θ T x ( i ) ) 2  最小二乘法 \text{令}J(\theta) = \frac{1}{2}\sum_{i=1}^m(y^{(i)}-\theta^Tx{(i)})^2\text{ 最小二乘法}\tag{2.6} J(θ)=21i=1m(y(i)θTx(i))2 最小二乘法(2.6)
从式2.5和2.6即可看出,为了让L(θ)最大,只需要让式2.6最小即可

2.2 目标函数求解

经过一系列的分析,我们已经得到我们的目标函数
(2.7) J ( θ ) = 1 2 ∑ i = 1 m ( y ( i ) − θ T x ( i ) ) 2 = 1 2 ( X θ − y ) T ( X θ − y ) \begin{aligned} J(\theta) &= \frac{1}{2}\sum_{i=1}^m(y^{(i)}-\theta^Tx{(i)})^2\\ &=\frac{1}{2}(X\theta-y)^T(X\theta-y)\\\tag{2.7} \end{aligned} J(θ)=21i=1m(y(i)θTx(i))2=21(Xθy)T(Xθy)(2.7)
我们需要找到一组θ来让目标函数取到最小值,又因为目标函数连续,所以这组θ一定为目标函数的驻点。此时,我们对目标函数求导
(2.8) ∇ θ J ( θ ) = ∇ θ ( 1 2 ( X θ − y ) T ( X θ − y ) ) = 1 2 ( 2 X T X θ − X T X − ( y T X ) T ) = X T X θ − X T y \begin{aligned} \nabla_\theta J(\theta) &= \nabla_\theta \left(\frac{1}{2}(X\theta-y)^T(X\theta-y)\right)\\ &=\frac{1}{2}\left(2X^TX\theta-X^TX-(y^TX)^T\right)\\ &=X^TX\theta - X^Ty\\\tag{2.8} \end{aligned} θJ(θ)=θ(21(Xθy)T(Xθy))=21(2XTXθXTX(yTX)T)=XTXθXTy(2.8)
令偏导等于0,最终我们得到参数θ的解析式
(2.9) θ = ( X T X ) − 1 X T y \theta = (X^TX)^{-1}X^Ty\tag{2.9} θ=(XTX)1XTy(2.9)

def standRegres(xArr,yArr):
	xMat = mat(xArr);yMat = mat(yArr).T
	xTx = xMat.T * xMat
	#判断矩阵是否可逆
	if linalg.det(xTx) == 0.0:
		print("This Matrix is singular,cannot do inverse")
		return
	#得到解析解
	theta= xTx.I*(xMat.T*yMat)
	return  theta

从上面实现代码可以看出,如果 ( X T X ) − 1 (X^TX)^{-1} (XTX)1不可逆则无法计算,那怎么办呢?
这时我们需要引入岭回归的概念,简单来说岭回归就是在矩阵XTX上加上一个 λ I \lambda I λI从而使得矩阵非奇异,进而能对 X T X + λ I X^TX+\lambda I XTX+λI求逆。此时参数 θ \theta θ的解析式为
(2.10) θ = ( X T X + λ I ) − 1 X T y \theta = (X^TX+\lambda I)^{-1}X^Ty\tag{2.10} θ=(XTX+λI)1XTy(2.10)

def ridgeRegres(xMat,yMat,lam=0.2):
	xTx = xMat.T * xMat
	#加上λI 从而使得矩阵非奇异
	denom = xTx + eye(shape(xMat)[1])*lam
	theta = denom.I * (xMat.T*yMat)
	return theta

2.3 梯度下降法

我们在2.2节中论述的 θ \theta θ解析解只适用于参数维数不大的情况,当参数维度过大,再使用这种方法就不合适了,所以我们使用另外一种方法:梯度下降算法。

2.3.1 梯度下降算法步骤

(2.11) J ( θ ) = 1 2 ∑ i = 1 m ( y ( i ) − θ T x ( i ) ) 2 J(\theta) = \frac{1}{2}\sum_{i=1}^m(y^{(i)}-\theta^Tx{(i)})^2\tag{2.11} J(θ)=21i=1m(y(i)θTx(i))2(2.11)

初始化theta,再沿着负梯度方向多次迭代更新 θ \theta θ每次选择一个更好的,直至收敛,最后可得到一个局部最优解。
(2.12) θ = θ − α δ J ( θ ) δ θ \theta = \theta - \alpha\frac{\delta J(\theta)}{\delta \theta}\tag{2.12} θ=θαδθδJ(θ)(2.12)

式中 α \alpha α表示学习率,学习率对结果会产生很大的影响,如果学习率设置过低则收敛速度很慢,如设置过高,则容易震荡难以收敛。

梯度下降多次迭代示意图

2.3.2 梯度下降算法分类

梯度下降算法根据每次迭代选择的样本数目不同可分为三类

  1. 批量梯度下降算法
    每次迭代都考虑到所以样本,容易得到最优解,但是速度很慢

(2.13) δ J ( θ ) δ θ j = − 1 m ∑ i = 1 m ( y i − h θ ( x i ) ) x j i \frac{\delta J(\theta)}{\delta \theta_j} = -\frac{1}{m}\sum_{i=1}^m (y^i - h_\theta(x^i))x_j^i\\\tag{2.13} δθjδJ(θ)=m1i=1m(yihθ(xi))xji(2.13)

θ j = θ j + 1 m ∑ i = 1 m ( y i − h θ ( x i ) ) x j i \theta _j = \theta _j + \frac{1}{m}\sum_{i=1}^m (y^i - h_\theta(x^i))x_j^i θj=θj+m1i=1m(yihθ(xi))xji

  1. 随机梯度下降算法
    每次迭代只找一个样本,迭代速度很快,但不一定每次都朝着收敛的方向

(2.14) θ j = θ j + ( y i − h θ ( x i ) ) x j i \theta _j = \theta _j + (y^i-h_\theta (x^i))x_j ^i \tag{2.14} θj=θj+(yihθ(xi))xji(2.14)

  1. 小批量梯度下降算法
    每次迭代从总数据中随机选择batch大小的数据进行计算,属于批量梯度下降和随机梯度下降的折中办法,比较实用。

θ j : = θ j − α 1 b a t c h S i z e ∑ k = i b a t c h S i z e ( h θ ( x ( k ) ) − y ( k ) ) x j ( k ) \theta _j :=\theta_j - \alpha\frac{1}{batchSize}\sum_{k=i}^{batchSize}(h_\theta(x^{(k)})-y^{(k)})x_j^{(k)} θj:=θjαbatchSize1k=ibatchSize(hθ(x(k))y(k))xj(k)

#使用SGD
	def trainSGD(self,X,Y,learningRate=1e-3,numIters=500,verbose=False):
		xArray = np.array(X)
		m,n= xArray.shape
		if self.w is None:
			self.w = np.ones(n)
		lossHistory = []
		for i in range(numIters):
			dataIndex = list(range(m))
			for j in range(m):
				learningRate = 4/(1.0+j+i) + 0.01
				randIndex = int(np.random.uniform(0,len(dataIndex)))
				h = np.dot(xArray[randIndex],self.w.T)
				loss = Y[0,randIndex] - h
				lossHistory.append(loss)
				self.w = self.w + learningRate*loss*X[randIndex]
				del(dataIndex[randIndex])
			if verbose and i%100 == 0:
				print("迭代次数:%d/%d loss: %f"%(i,numIters,lossHistory[-1]))
		return lossHistory

#使用BGD
	def trainBGD(self,X,Y,learningRate=1e-3,reg=0.0,numIters=1000,verbose=False):
		m,n = X.shape
		xArray = np.array(X)
		if self.w is None:
			self.w = np.ones((n,1))
		lossHistory = []
		for i in range(numIters):
			h = np.dot(xArray,self.w)
			loss = Y[0].T-h
			self.w = self.w + learningRate*np.dot(xArray.T,loss)
			lossHistory.append(np.sum(loss))
			if verbose and i%100==0:
				print("迭代次数:%d/%d  loss:%f"%(i,numIters,np.sum(loss)))

		return lossHistory

代码点此获取GitHub

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值