机器学习_手写算法:随机梯度下降实现线性回归

1、数据准备

# 生成随机散点
import numpy as np
x = 2 * np.random.rand(100, 1)
y = 6 + 5 * x + np.random.rand(100,1)  # 添加噪声

# 图示
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.scatter(x, y, s=2, c='red',alpha=0.7)
plt.show()

生成散点如下:
机器学习_手写算法:随机梯度下降实现线性回归_第1张图片

2、随机梯度下降寻找参数

# y = wx +b
# 将b值初始定为 w2 * 1, 让其同时迭代
x_b = np.c_[np.ones((10, 1)), x] # 合并列

采用动态学习率,使其逐步减小:

def eta_new(t):
    """
    t : 迭代次数
    限定最低学习率 0.01
    4 和 1为人为定值
	"""
	return 4/(1 + t) +0.01

随机梯度下降:

n = 1000  # 迭代次数
w = np.random.randn(2,1) # 随机定w的初始值

# 开始随机梯度下降
for time in range(n):
	for index in range(1,len(x)):          # 浏览全部索引
		r_index = np.random.randint(index) # 随机提取
		xi = x_b[r_index : r_index+1]      # 随机取样本
        yi = y[r_index : r_index+1] 
        eta = eta_new(time + index)        # 学习率跟随迭代次数和索引浮动变化,总体趋势为逼近0.01
        td = xi.T.dot(xi.dot(w) - yi)
        w -= eta * td

经过一千次随机迭代后,绘图查看迭代效果

# w 参数为 array([[6.60615545],
#               [4.93099413]])

plt.scatter(x, y, s=2, c='red',alpha=0.7) # 原数据
plt.plot(x, x_b.dot(w), c = 'steelblue', alpha =0.6)  # 迭代后的拟合数据
plt.show()

机器学习_手写算法:随机梯度下降实现线性回归_第2张图片

3、sklearn 线性回归和最小二乘发

# 用最小二乘方法进行计算 w 和 b 
w_r = (len(x)*sum(x*y) -sum(x)*sum(y) ) / (len(x)*sum(x*x) - sum(x)**2)
b_r = np.mean(y)- w_r*np.mean(x)
## 结果为 : w_r = 4.91148394 ;b_r = 6.60282153

# sklear线性回归
from sklearn.linear_model import LinearRegression
lr = LinearRegression(fit_intercept=False)
lr.fit(x_b, y)
lr.coef_  #  array([[6.60282153, 4.91148394]]) 结果同最小二乘法

比较线性回归和随机梯度下降的差距

y_pre = lr.predict(x_b)

plt.scatter(x, y, s=2, c='red',alpha=0.7)
plt.plot(x, x_b.dot(w), c = 'steelblue', alpha =0.6)
plt.plot(x, y_pre, c = 'green', alpha = 0.6)
plt.show()

机器学习_手写算法:随机梯度下降实现线性回归_第3张图片

由图可见:SGD 和线性回归的拟合几乎重叠
从参数上来看也几乎相同
SGD —— ·[6.60615545], [4.93099413]
线性回归 —— [6.60282153, 4.91148394]

4、为什么线性回归可以用梯度下降的方法去拟合

首先,从最小二乘法和线性回归所得的参数结果可以知晓,两者是进行同样的算法操作。
由于,最小二乘法是由方差求一阶偏导为零,推导出来的。(推导相对简单,自行百度)
而梯度下降是常见的一阶优化方法(具有一阶连续偏导),目的也是为了使得方差收敛到最小。
方差: [具有一阶连续偏导]
D = ∑ i = 1 n ( y i − x i ⋅ w ) 2 D = \sum_{i=1}^n{(y_i-x_i\cdot{w})^2} D=i=1n(yixiw)2
因此可以用选取适当的初始值 w 0 w_0 w0,不断迭代,更新 w w w的值,进行目标函数的极小化,直到收收敛,从而达到减小函数值的目的。

5、梯度下降原理

只要不断执行以下过程即可收敛到局部极小
f ( x t + 1 ) < f ( x t ) , t = 0 , 1 , 2.... f(x^{t+1} )f(xt+1)<f(xt),t=0,1,2....

根据泰勒展开可得(舍掉高阶无穷小项以后——局部线性近似公式)回顾泰勒展开:
f ( x + Δ x ) ≈ f ( x ) + Δ x T ∇ f ( x ) f(x+\Delta{x} )\approx{f(x) + \Delta{x}^T \nabla{f(x)}} f(x+Δx)f(x)+ΔxTf(x)

要使得 f ( x t + 1 ) = f ( x t + Δ x ) < f ( x t ) f(x^{t+1} ) = f(x^t+\Delta{x} )f(xt+1)=f(xt+Δx)<f(xt),且最快下降(推倒参考),需要使得 Δ x T = − λ ∇ f ( x ) \Delta{x}^T = -\lambda \nabla{f(x)} ΔxT=λf(x),即 $x^{t+1} -x^t =-\lambda \nabla{f(x)} $,最终得到:
x t + 1 = x t − λ ∇ f ( x ) x^{t+1} =x^t -\lambda \nabla{f(x)} xt+1=xtλf(x)

由于只关注 x x x的值,且在知道其为凸函数的时候,可以直接这样简单快速迭代
方差的梯度函数为:(由于多次迭代,可以忽略常数项,相当于将其算入学习率)
∇ f ( w ) = 2 ∑ i = 1 n x i ( y i − x i ⋅ w ) \nabla{f(w)}= 2\sum_{i=1}^n{x_i(y_i-x_i\cdot{w})} f(w)=2i=1nxi(yixiw)
即逐步移动 w w w,使 f ( w t ) f(w^t) f(wt)其达到最小值

参考 李航 《统计学习方法》
参考 周志华 《机器学习》

6、利用sklearn中的SGDRegressor,快速进行梯度下降线性回归

其默认优化的是均方差损失函数

from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(N_ilter = 50,   # 迭代次数
					   penalty = None, # 正则项为空
					   eta0 = 0.1      # 学习率
					   )
sgd_reg.fit(x,y)
sgd_reg.intercept_ , sgd_reg.coef_
## 结果 6.59849714, 4.90377178 

其结果同 线性回归基本相同,增加迭代次数还可以优化

你可能感兴趣的:(机器学习,机器学习,梯度下降,线性回归,python,sklearn)