线性回归
线性回归公式:$h_θ$ = $θ_0$ + $θ_1x$
平方差代价函数:$J(θ)$ = $\frac1{2m}\sum_{i=1}^{m}{(h_θ(x^{(i)}) - y^{(i)})}^2$
梯度下降
$θ_j := θ_j - α\frac∂ {∂ θ_j}J(θ_0,θ_1)$
使用上面的公式不断的更新代价函数$J(θ)$,直到$J(θ)$收敛或者不再发散,其中:
$\frac∂ {∂ θ_j}J(θ_0,θ_1)$ = $\frac∂{∂θ_j}\frac1{2m} \sum_{i=1}^{m}(θ_0 +θ_1x^{(i)} - y^{(i)})^2$
$j = 0:\frac∂ {∂ θ_0}J(θ_0,θ_1) = \frac1m\sum_{i=1}^{m}(h_θ(x^{(i)}) - y^{(i)})$
$j = 1:\frac∂ {∂ θ_1}J(θ_0,θ_1) = \frac1m\sum_{i=1}^{m}(h_θ(x^{(i)}) - y^{(i)}) * x^{(i)}$
算出代价函数$j$的斜率后,将其代回梯度下降算法,代入之后的线性回归的梯度下降算法为: $θ_0 := θ_0 - α\frac1m\sum_{i=1}^{m}(h_θ(x^{(i)}) - y^{(i)})$
$θ_1 := θ_1 -α\frac1m\sum_{i=1}^{m}(h_θ(x^{(i)}) - y^{(i)}) * x^{(i)}$
不断重复该过程直到收敛或者不再发散。
python代码实现
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
def h(xita0,xita1,data):
data['y_pre'] = xita0 + data['x']*xita1
j0 = (1/(data.shape[0])*2) * sum(data['y_pre'] - data['y'])
j1 = (1/(data.shape[0])*2) * sum((data['y_pre'] - data['y']) * data['x'])
return j0,j1
def j(data,aerfa=0.001,max_iters=100000,precision=0.00001):
xita0 = 0
xita1 = 0
for i in range(max_iters):
print('xita0,xita1:',xita0,xita1)
j0,j1 = h(xita0,xita1,data)
print(j0,j1)
if abs(j1) < precision:
break
xita0 = xita0 - aerfa * j0
xita1 = xita1 - aerfa * j1
print(i)
return xita0,xita1
num_points = 1000
vectors_set = []
for i in range(num_points):
x1 = np.random.normal(0.0, 0.55)
y1 = x1 * 0.5 + 0.5 + np.random.normal(0.0, 0.03)
vectors_set.append([x1, y1])
data = pd.DataFrame(vectors_set,columns=['x','y'])
xita0,xita1 = j(data)
x_data = [v[0] for v in vectors_set]
y_data = [v[1] for v in vectors_set]
y_pre = [xita0 + xita1*v[0] for v in vectors_set]
plt.scatter(x_data,y_data,c='b')#c表示颜色
plt.plot(x_data,y_pre)
plt.show()
复盘
平方差代价函数:$J(θ)$ = $\frac1{2m}\sum_{i=1}^{m}{((θ_0 + θ_1x) - y^{(i)})}^2$ 梯度下降法求解的过程就是通过不断的迭代,通过不同的$θ_0 和 θ_1$的组合,来求$J(θ)$的值,使得$J(θ)$最小的那个组合,就是线性回归模型中最优的$θ_0 和 θ_1$。 下面,我们使用python来求解:
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
def surface3d_data():
'''我们从0到1易0.05的步长迭代不同的θ_0(x)和 θ_1(y)的组合,来计算代价值(z)'''
for t0 in float_range(0, 1, 0.05):
x = float(t0)
for t1 in float_range(0, 1, 0.05):
y = float(t1)
z = round((1/(data.shape[0])*2) * sum(np.square((x + y*data['x'])-data['y'])),4)
yield [x, y, z]
def draw(x, y, z):
'''采用matplolib绘制曲面图:param x: x轴坐标数组:param y: y轴坐标数组:param z: z轴坐标数组:return:'''
X = x
Y = y
Z = z
fig = plt.figure(figsize=(30,30))
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(X, Y, Z)
plt.show()
res = list(surface3d_data())
df = pd.DataFrame(res,columns=['xita0','xita1','j'])
#查看使得代价函数最小的'xita0','xita1'是多少
print(df.loc[df.j.idxmin(),:])
# 输出结果为:
# xita0 0.5000
# xita1 0.5000
# j 0.0009
# 和我们生成随机数点的公式相同,如下:
# y1 = x1 * 0.5 + 0.5 + np.random.normal(0.0, 0.03)
x = [v[0] for v in res]
y = [v[1] for v in res]
z = [v[2] for v in res]
draw(x, y, z) #画出代价函数的曲面图
通过观察可得,曲面大概在x = 0.5,y = 0.5点的点上取得最小值。