批量梯度下降&正规方程
前言
对于求解线性回归问题,尤其是多变量线性回归,可以使用批量梯度下降,也可以使用正规方程来求解,本篇主要对这两种方法进行介绍,并比较二者的特点以及使用方法。
一、批量梯度下降(Batch Gradient Descent)
1.算法介绍
本篇以多变量线性回归为例,对于给定的
m
m
m组包含
n
n
n个特征的变量
X
X
X(
x
j
(
i
)
x_j^{(i)}
xj(i)表示第
i
i
i行、第
j
j
j个特征值),和
m
m
m个目标值
y
y
y,拟合的回归方程为:
h
θ
(
x
)
=
θ
0
+
θ
1
x
1
+
θ
2
x
2
+
⋯
+
θ
n
x
n
h_{\theta}(x)=\theta_0+\theta_1x_1+\theta_2x_2+ \cdots +\theta_nx_n
hθ(x)=θ0+θ1x1+θ2x2+⋯+θnxn
为简化公式,令
x
0
=
1
x_0=1
x0=1,则矩阵X的维度变为
m
∗
(
n
+
1
)
m*(n+1)
m∗(n+1),上式可写为矩阵形式:
h
θ
(
x
)
=
θ
T
X
h_{\theta}(x)=\theta^TX
hθ(x)=θTX
构建的代价函数为(cost function):
J
(
θ
0
,
θ
1
,
⋯
,
θ
n
)
=
1
2
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
J(\theta_0, \theta_1,\cdots, \theta_n)=\frac{1}{2m}\sum_{i=1}^m(h_{\theta}(x^{(i)})-y^{(i)})^2
J(θ0,θ1,⋯,θn)=2m1i=1∑m(hθ(x(i))−y(i))2
对应的批量梯度下降算法公式如下,其中
α
\alpha
α 为学习率,表示每次移动的步长大小,注意更新
n
+
1
n+1
n+1 个
θ
\theta
θ 值时,需要同步更新,因此才称之为批量梯度下降。
θ
j
:
=
θ
j
−
α
∂
J
(
θ
0
,
θ
1
,
⋯
,
θ
n
)
∂
θ
j
=
θ
j
−
α
∂
∂
θ
j
(
1
2
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
)
=
θ
j
−
α
1
m
∑
i
=
1
m
(
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
⋅
x
j
(
i
)
)
,
f
o
r
j
=
0
,
1
,
⋯
,
n
.
\theta_j:=\theta_j-\alpha\frac{\partial J(\theta_0, \theta_1,\cdots, \theta_n)}{\partial \theta_j}\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\theta_j-\alpha\frac{\partial}{\partial \theta_j}(\frac{1}{2m}\sum_{i=1}^m(h_{\theta}(x^{(i)})-y^{(i)})^2)\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\theta_j-\alpha\frac{1}{m}\sum_{i=1}^m((h_{\theta}(x^{(i)})-y^{(i)})\cdot x_j^{(i)}),\ for\ j=0,1,\cdots, n.
θj:=θj−α∂θj∂J(θ0,θ1,⋯,θn) =θj−α∂θj∂(2m1i=1∑m(hθ(x(i))−y(i))2) =θj−αm1i=1∑m((hθ(x(i))−y(i))⋅xj(i)), for j=0,1,⋯,n.
2.Python代码
import numpy as np
import random
from numpy import genfromtxt
def getData(dataSet):
m, n = np.shape(dataSet)
trainData = np.ones((m, n))
trainData[:,:-1] = dataSet[:,:-1] #第一列到倒数第二列为X,共n-1列,加上最后一列补为1,共为n列
trainLabel = dataSet[:,-1] #最后一列为y
return trainData, trainLabel
def batchGradientDescent(x, y, theta, alpha, m, maxIterations):
xTrains = x.transpose()
for i in range(0, maxIterations):
hypothesis = np.dot(x, theta)
loss = hypothesis - y
# print loss
gradient = np.dot(xTrains, loss) / m
theta = theta - alpha * gradient
return theta
def predict(x, theta):
m, n = np.shape(x)
xTest = np.ones((m, n+1))
xTest[:, :-1] = x
yP = np.dot(xTest, theta)
return yP
dataPath = r"E:\learning\house.csv" #数据集路径,为避免各特征尺度不同,在导入之前可先将数据集归一化
dataSet = genfromtxt(dataPath, delimiter=',')
trainData, trainLabel = getData(dataSet) #从中提取X,y
m, n = np.shape(trainData) #训练数据集,m行n列,其中最后一列全为1
theta = np.ones(n) #初始化theta
alpha = 0.1 #学习率,可以尝试0.01,0.03,0.1,0.3,1,3,10
maxIteration = 5000 #最大迭代次数
theta = batchGradientDescent(trainData, trainLabel, theta, alpha, m, maxIteration)
x = np.array([[3.1, 5.5], [3.3, 5.9], [3.5, 6.3], [3.7, 6.7], [3.9, 7.1]]) #测试数据集,列数为特征值数
print predict(x, theta) #输出测试集的目标预测值
3.正则化优化
正则化线性回归函数的代价函数为:
J
(
θ
)
=
1
2
m
∑
i
=
1
m
[
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
+
λ
∑
j
=
1
n
θ
j
2
]
J(\theta)=\frac{1}{2m}\sum_{i=1}^m[(h_{\theta}(x^{(i)})-y^{(i)})^2+\lambda\sum_{j=1}^n\theta_j^2]
J(θ)=2m1i=1∑m[(hθ(x(i))−y(i))2+λj=1∑nθj2]
求导后得到对应批量梯度下降算法的公式:
θ
0
:
=
θ
0
−
α
1
m
∑
i
=
1
m
[
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
0
(
i
)
]
θ
j
:
=
θ
j
−
α
[
1
m
∑
i
=
1
m
(
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
)
+
λ
m
θ
j
]
,
f
o
r
j
=
1
,
2
,
⋯
,
n
.
\theta_0:=\theta_0-\alpha \frac{1}{m} \sum_{i=1}^{m}[(h_{\theta}(x^{(i)})-y^{(i)})x_0^{(i)}] \\ \theta_j:=\theta_j-\alpha [\frac{1}{m} \sum_{i=1}^{m}((h_{\theta}(x^{(i)})-y^{(i)})x_j^{(i)})+\frac{\lambda}{m}\theta_j], for \ j=1,2,\cdots,n.
θ0:=θ0−αm1i=1∑m[(hθ(x(i))−y(i))x0(i)]θj:=θj−α[m1i=1∑m((hθ(x(i))−y(i))xj(i))+mλθj],for j=1,2,⋯,n.
二、正规方程(Normal Equation)
1.算法介绍
对于上述代价函数,将其用矩阵表示出来,即为
J
(
θ
)
=
1
2
(
X
θ
−
y
)
2
J(\theta)=\frac{1}{2} (X\theta-y)^2
J(θ)=21(Xθ−y)2,其中
X
X
X为
m
m
m行
n
n
n列,
θ
\theta
θ为
n
n
n行1列,
y
y
y为
m
m
m行1列,可将其展开写成如下形式:
J
(
θ
)
=
1
2
(
X
θ
−
y
)
T
(
X
θ
−
y
)
=
1
2
(
θ
T
X
T
−
y
T
)
(
X
θ
−
y
)
=
1
2
(
θ
T
X
T
X
θ
−
θ
T
X
T
y
−
y
T
X
θ
+
y
T
y
)
J(\theta)=\frac{1}{2} (X\theta-y)^T (X\theta-y)=\frac{1}{2} (\theta^TX^T-y^T) (X\theta-y)=\frac{1}{2}(\theta^TX^TX\theta-\theta^TX^Ty-y^TX\theta+y^Ty)
J(θ)=21(Xθ−y)T(Xθ−y)=21(θTXT−yT)(Xθ−y)=21(θTXTXθ−θTXTy−yTXθ+yTy)
下面求
J
(
θ
)
J(\theta)
J(θ)对
θ
\theta
θ的偏导数,得到:
∂
J
(
θ
)
∂
θ
=
X
T
X
θ
−
X
T
y
\frac{\partial J(\theta)}{\partial \theta}=X^TX\theta-X^Ty
∂θ∂J(θ)=XTXθ−XTy
令
∂
J
(
θ
)
∂
θ
=
0
\frac{\partial J(\theta)}{\partial \theta}=0
∂θ∂J(θ)=0,得到
θ
=
(
X
T
X
)
−
1
X
T
y
\theta=(X^TX)^{-1}X^Ty
θ=(XTX)−1XTy
需要注意的是,使用该算法时,需要考虑
X
T
X
X^TX
XTX是否可逆,对于某些不可逆的情况(①特征之间不独立;②特征数量大于训练集的数量),该方法不可用。
2.Python代码
import numpy as np
import random
from numpy import genfromtxt
def getData(dataSet):
m, n = np.shape(dataSet)
trainData = np.ones((m, n))
trainData[:,:-1] = dataSet[:,:-1] #第一列到倒数第二列为X,共n-1列,加上最后一列补为1,共为n列
trainLabel = dataSet[:,-1] #最后一列为y
return trainData, trainLabel
def normalEqu(x, y):
a = numpy.linalg.pinv(np.dot(x.T,x))
b = np.dot(a,x.T)
theta = np.dot(b,y)
return theta
def predict(x, theta):
m, n = np.shape(x)
xTest = np.ones((m, n+1))
xTest[:, :-1] = x
yP = np.dot(xTest, theta)
return yP
dataPath = r"E:\learning\house.csv" #数据集路径,为避免各特征尺度不同,在导入之前可先将数据集归一化
dataSet = genfromtxt(dataPath, delimiter=',')
trainData, trainLabel = getData(dataSet) #从中提取X,y
m, n = np.shape(trainData) #训练数据集,m行n列,其中最后一列全为1
theta = normalEqu(trainData, trainLabel)
x = np.array([[3.1, 5.5], [3.3, 5.9], [3.5, 6.3], [3.7, 6.7], [3.9, 7.1]]) #测试数据集,列数为特征值数
print predict(x, theta) #输出测试集的目标预测值
3.正则化优化
利用正规方程来求解正则化线性回归模型,方法如下所示:
θ
=
(
X
T
X
+
λ
[
0
1
1
⋱
1
]
)
−
1
X
T
y
\theta=\left( X^TX+\lambda \left [ \begin{array}{ccccc} 0& & & & \\ &1& & & \\ & &1& & \\ & & &\ddots& \\ & & & &1\\ \end{array} \right ]\right)^{-1}X^Ty
θ=⎝⎜⎜⎜⎜⎛XTX+λ⎣⎢⎢⎢⎢⎡011⋱1⎦⎥⎥⎥⎥⎤⎠⎟⎟⎟⎟⎞−1XTy