线性回归
线性回归是指:给定数据集D={
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
m
,
y
m
)
(x^ 1, y^1), (x^2, y^2), ... , (x^m, y^m)
(x1,y1),(x2,y2),...,(xm,ym) },试图使用线性函数
h
w
(
x
)
=
w
0
+
w
1
x
1
+
.
.
.
+
w
n
x
n
h_w(x)=w_0+w_1x_1+...+w_nx_n
hw(x)=w0+w1x1+...+wnxn来尽可能准确地预测出x所对应的y值。(其中
x
1
表
示
[
x
1
1
,
x
2
1
,
.
.
.
,
x
n
1
]
x^1表示[x^1_1, x^1_2, ... , x^1_n]
x1表示[x11,x21,...,xn1]向量)
那么如何确定
w
0
和
w
1
w_0和w_1
w0和w1的值呢?显然需要使得
h
w
(
x
)
h_w(x)
hw(x)的值尽可能地接近y,这里常用的方法是使两者的方差最小化。由此定义代价函数
J
(
w
)
=
∑
i
=
1
m
(
h
w
(
x
i
)
−
y
i
)
2
J(w)=\sum_{i=1}^m(h_w(x^i)-y^i)^2
J(w)=i=1∑m(hw(xi)−yi)2
求得J(w)的最小值常用的有梯度下降算法和特征方程法。
梯度下降算法
梯度下降算法就是通过不停地寻找局部最小值来逼近全局的最小值,开始时我们随机选择一个参数的组合
(
w
0
,
w
1
,
.
.
.
,
w
n
)
(w_0, w_1, ... , w_n)
(w0,w1,...,wn),计算代价函数,然后我们寻找下一个能让代价函数下降最多的参数组合。
do {
for j=0 to n {
w
j
=
w
j
−
a
∂
J
(
w
)
∂
w
j
w_j = w_j - a\frac{\partial J(w)}{\partial w_j}
wj=wj−a∂wj∂J(w)
}
} while (not convergence);
其中a为learning rate,决定
w
j
w_j
wj往当前方向下降的大小,其值越大收敛越快,但过大时也有可能错过最小值点。
- 缩小x的取值范围能提高收敛速度。
- 对a尝试不同的值 ,尽可能选出最优值。
- 对x定义新的模型有时会得到更好的结果。
特征方程法
要求J(w)的最小值,很容易想到的就是对J(w)求偏导,然后找出可能的极值点。记
w
=
[
w
0
,
w
1
,
.
.
.
,
w
n
]
T
w=[w_0, w_1, ... , w_n]^T
w=[w0,w1,...,wn]T,
y
=
[
y
1
,
y
2
,
.
.
.
,
y
m
]
T
y=[y^1, y^2, ... , y^m]^T
y=[y1,y2,...,ym]T,
X
m
∗
(
n
+
1
)
=
[
1
,
x
1
i
,
x
2
i
,
.
.
.
,
x
n
i
]
T
X_{m*(n+1)}=[1, x^i_1, x^i_2, ... , x^i_n]^T
Xm∗(n+1)=[1,x1i,x2i,...,xni]T,则
h
w
(
x
)
=
X
w
h_w(x)=Xw
hw(x)=Xw,
J
(
w
)
=
(
X
w
−
y
)
T
(
X
w
−
y
)
J(w)=(Xw-y)^T(Xw-y)
J(w)=(Xw−y)T(Xw−y)。对J(w)求导:
∂
J
(
w
)
∂
w
=
∂
(
X
w
−
y
)
T
(
X
w
−
y
)
∂
w
\frac{\partial J(w)}{\partial w}=\frac{\partial (Xw-y)^T(Xw-y)}{\partial w}
∂w∂J(w)=∂w∂(Xw−y)T(Xw−y)
=
∂
(
X
w
−
y
)
∂
w
∂
(
X
w
−
y
)
T
(
X
w
−
y
)
∂
(
X
w
−
y
)
=\frac{\partial (Xw-y)}{\partial w}\frac{\partial (Xw-y)^T(Xw-y)}{\partial (Xw-y)}
=∂w∂(Xw−y)∂(Xw−y)∂(Xw−y)T(Xw−y)
=
2
X
T
(
X
w
−
y
)
=2X^T(Xw-y)
=2XT(Xw−y)
令
∂
J
(
w
)
∂
w
=
0
\frac{\partial J(w)}{\partial w}=0
∂w∂J(w)=0,解得
w
=
(
X
T
X
)
−
1
X
T
y
w=(X^TX)^{-1}X^Ty
w=(XTX)−1XTy。若
X
T
X
X^TX
XTX是不可逆矩阵,则求它的伪逆。下面是python代码实现:
import numpy as np
def loadDataSet(filename):
numFeat = len(open(filename).readline().split('\t')) - 1
dataMat = []
labelMat = []
fr = open(filename)
for line in fr.readlines():
lineArr = []
curLine = line.strip().split('\t')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return dataMat, labelMat
def standRegres(xArr, yArr):
xMat = mat(xArr)
yMat = mat(yArr).T
xTx = xMat.T * xMat
ws = linalg.pinv(xTx) * (xMat.T * yMat)
return ws
if __name__ = '__main__':
xArr, yArr = loadDataSet('ex0.txt')
ws = standRegres(xArr, yArr)
xMat = mat(xArr)
yMat = mat(yArr)
xCopy = xMat.copy()
xCopy.sort(0)
yHat = xCopy * ws
print(corrcoef(yHat.T, yMat))
两方法的差别
梯度下降 | 特征方程 |
---|---|
需要选择合适的a | 不需要选择a |
需要多次迭代计算 | 不需迭代 |
当n比较大时仍表现良好 | 需要计算 X T X X^TX XTX,当n过大效率明显下降 |