什么是梯度下降,举个栗子,(假设地面无障碍物)我们在山顶丢一个网球,啪,一下就越过这个坡了,然后在另一个沟里来回跳动,一直到达最低点。那么问题来了,这这里在跳跃的过程中,直接越过第一个坡度。这样的结果就是使得我们的小球无法到达最低点,对应到程序上就是我们在梯度下降的时候无法找到最优值。

                                                           

Python的梯度提升决策分类 python 梯度下降算法_Python的梯度提升决策分类

梯度下降,就是是在不断就是出于最高点,先下走一个步长,不断的走,或回撤步长的过程。使得我们找到目标的最优值。那么有个问题就是步长(也称为学习率)取值为多少才适合? 过大的步长容易使得跳过最优值,过小的步长使得梯度下降的效率过低。

梯度下降的过程,其实就是迭代求解的过程.

在公式推导之前,我们先引入预测值函数

                                                      

Python的梯度提升决策分类 python 梯度下降算法_梯度下降_02

                                         hθ(x) :预测值           θ1 :权重                           θ0 :偏置

 还有,损失函数(也叫代价函数)

                                         

Python的梯度提升决策分类 python 梯度下降算法_权重_03

该损失函数是由高斯分布的预测误差求取对数拟然函数,结果的被减项得出的.原结果1/2并不是1/2m,这里分母加了m,是为了去除样本对损失函数的影响,是的减少样本数对损失函数的影响. (这里如果为加1/m,结果将是样本次数越多,损失函数越大,样本对损失函数的影响非常大.)

 

根据损失函数,我们接下来对 权重θ1 与 偏置 θ0 ,求取对应的偏导数.

                                                         

Python的梯度提升决策分类 python 梯度下降算法_Python的梯度提升决策分类_04

                                                

Python的梯度提升决策分类 python 梯度下降算法_梯度下降_05

上面的  α 就是我们设置的学习率.

 

接下来我们将使用高尔夫球的案例来写梯度下降的算法.

链接:https://pan.baidu.com/s/1GJ20Kha2AMF5Qw0hRUarVQ 
提取码:0fjw 
数据集我保存到云盘,需要的可以自己下载一下

#梯度下降
import pandas
import matplotlib.pyplot as plt

# 高尔夫球数据集
pga = pandas.read_csv("pga.csv")


# 数据标准化
pga.distance = (pga.distance - pga.distance.mean()) / pga.distance.std()
pga.accuracy = (pga.accuracy - pga.accuracy.mean()) / pga.accuracy.std()
print(pga.head())

plt.scatter(pga.distance, pga.accuracy)
plt.xlabel('normalized distance')
plt.ylabel('normalized accuracy')
plt.show()

 

Python的梯度提升决策分类 python 梯度下降算法_权重_06

 

##distance: 挥杆之后的距离

## accuracy : 精度

# accuracyi=θ1distancei+θ0+ϵ

from sklearn.linear_model import LinearRegression
import numpy as np

# We can add a dimension to an array by using np.newaxis
print("Shape of the series:", pga.distance.shape)
print("Shape with newaxis:", pga.distance[:, np.newaxis].shape)

# fit()中的X变量必须是二维的
lm = LinearRegression()
lm.fit(pga.distance[:, np.newaxis], pga.accuracy)
theta1 = lm.coef_[0]
print (theta1)

 

Python的梯度提升决策分类 python 梯度下降算法_Python的梯度提升决策分类_07

 

# 单变量线性模型的成本函数
# hθ(x) = θ1X + θ0
#计算损失函数,J(θ0,θ1) = 1/2m *累加 (hθ(Xi)-Yi)**2
def cost(theta0, theta1, x, y):
    # 初始化成本
    J = 0
    # 观测次数
    m = len(x)
    # 遍历每个观测值
    for i in range(m):
        # 计算假设 
        h = theta1 * x[i] + theta0
        # 累加成本
        J += (h - y[i])**2
    # 平均和规范成本
    J /= (2*m)
    return J

# 损失函数 theta0=0 and theta1=1
print(cost(0, 1, pga.distance, pga.accuracy))

theta0 = 100
theta1s = np.linspace(-3,2,100)
costs = []
for theta1 in theta1s:
    costs.append(cost(theta0, theta1, pga.distance, pga.accuracy))

plt.plot(theta1s, costs)
plt.show()

Python的梯度提升决策分类 python 梯度下降算法_损失函数_08

import numpy as np
from mpl_toolkits.mplot3d import Axes3D

# 使用Matplotlib的地表绘图示例
# 创建x和y变量
x = np.linspace(-10,10,100)
y = np.linspace(-10,10,100)

# 我们必须创建变量来表示x和y中每一对可能的点
# ie. (-10, 10), (-10, -9.8), ... (0, 0), ... ,(10, 9.8), (10,9.8)
# x和y需要转换成100x100矩阵来表示这些坐标
# np.meshgrid will build a coordinate matrices of x and y
X, Y = np.meshgrid(x,y)
#print(X[:5,:5],"\n",Y[:5,:5])

# 计算一个三维抛物线
Z = X**2 + Y**2 

# 打开一个画布
fig = plt.figure()
# I初始化3 d图
ax = fig.gca(projection='3d')
# 绘制图像
ax.plot_surface(X=X,Y=Y,Z=Z)

plt.show()

 
theta0s = np.linspace(-2,2,100)
theta1s = np.linspace(-2,2, 100)
COST = np.empty(shape=(100,100))
# Meshgrid为参数
T0S, T1S = np.meshgrid(theta0s, theta1s)
# 累计每个参数组合计算成本
for i in range(100):
    for j in range(100):
        COST[i,j] = cost(T0S[0,i], T1S[j,0], pga.distance, pga.accuracy)

# 绘制3d图
fig2 = plt.figure()
ax = fig2.gca(projection='3d')
ax.plot_surface(X=T0S,Y=T1S,Z=COST)
plt.show()

Python的梯度提升决策分类 python 梯度下降算法_权重_09

#假设函数的权重求导
def partial_cost_theta1(theta0, theta1, x, y):
    # 假设函数
    h = theta0 + theta1*x
    # 对θ1求导后的公式进行计算,θ1的偏导数
    diff = (h - y) * x
    # 累加偏导数和,除于样本个数
    partial = diff.sum() / (x.shape[0])
    return partial

partial1 = partial_cost_theta1(0, 5, pga.distance, pga.accuracy)
print("partial1 =", partial1)


#假设函数的偏置求导
def partial_cost_theta0(theta0, theta1, x, y):
    # 假设函数
    h = theta0 + theta1*x
    # 对θ0求导后的公式进行计算,θ1的偏导数
    diff = (h - y)
    # 累加偏导数和,除于样本个数
    partial = diff.sum() / (x.shape[0])
    return partial

partial0 = partial_cost_theta0(1, 1, pga.distance, pga.accuracy)

Python的梯度提升决策分类 python 梯度下降算法_Python的梯度提升决策分类_10

 

# x是特征向量 -- distance
# y 是目标标签 -- accuracy
# alpha 是学习率
# theta0 是偏置
# theta1 是权重
def gradient_descent(x, y, alpha=0.1, theta0=0, theta1=0):
    max_epochs = 1000 # 最大迭代次数
    counter = 0      # 计数器
    c = cost(theta1, theta0, pga.distance, pga.accuracy)  ## 损失函数
    costs = [c]     # 储存损失函数
    # 设置收敛阈值,找出代价函数在何处最小
    # 以前成本与当前成本之差,小于这个值我们就说参数收敛了,即已经快找点目标了    
    convergence_thres = 0.000001  #收敛的阈值
    cprev = c + 10   #这里加10是为了设置一个起始值,要计算起始值与损失函数的距离
    theta0s = [theta0]
    theta1s = [theta1]

    # 当成本收敛或我们遇到大量迭代时,我们将停止更新
    while (np.abs(cprev - c) > convergence_thres) and (counter < max_epochs):
        cprev = c #这里把损失函数的值赋给了起始值,使得范围进一步缩小
        # 学习率乘与对θ求导
        update0 = alpha * partial_cost_theta0(theta0, theta1, x, y)
        update1 = alpha * partial_cost_theta1(theta0, theta1, x, y)

        # 同时更新theta0和theta1
        # 我们想要在同一组假设参数下计算斜率,所有要求出偏导后再更新     
        theta0 -= update0
        theta1 -= update1
        
        # 保存 thetas
        theta0s.append(theta0)
        theta1s.append(theta1)
        
        # 计算新损失函数
        c = cost(theta0, theta1, pga.distance, pga.accuracy)

        # 保存更新
        costs.append(c)
        counter += 1   # Count

    return {'theta0': theta0, 'theta1': theta1, "costs": costs}

print("Theta1 =", gradient_descent(pga.distance, pga.accuracy)['theta1'])#输出权重
descend = gradient_descent(pga.distance, pga.accuracy, alpha=.01)
plt.scatter(range(len(descend["costs"])), descend["costs"])
plt.show()

Python的梯度提升决策分类 python 梯度下降算法_权重_11