梯度提升(GBDT)实战


本文环境为notebook

1.梯度下降

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# 定义目标函数,二次函数
f = lambda x : (x - 3)**2 + 2.5*x -7.5
# 导数 = 梯度,求解导数令导数=0求解最小值
# 2*(x - 3)*1 + 2.5 = 0
# 2*x - 3.5 = 0
# x = 1.75
x = np.linspace(-2,5,100)
y = f(x)
plt.plot(x,y)

在这里插入图片描述
梯度下降求解最小值

# 导数函数
d = lambda x : 2*(x - 3) + 2.5
# 学习率,每次改变数值的时候,改变多少
learning_rate = 0.1
# min_value瞎蒙的值,方法,最快的速度找到最优解(梯度下降)
min_value = np.random.randint(-3,5,size = 1)[0]
print('-------------------',min_value)
# 记录数据更新了,原来的值,上一步的值,退出条件
min_value_last = min_value + 0.1
# tollerence容忍度,误差,在万分之一,任务结束
tol = 0.0001
count = 0
while True:
    if np.abs(min_value - min_value_last) < tol:
        break
#     梯度下降
    min_value_last = min_value
#     更新值:梯度下降
    min_value = min_value - learning_rate*d(min_value)
    count +=1
    print('+++++++++++++++++++++%d'%(count),min_value)
print('**********************',min_value)

在这里插入图片描述

2.梯度提升

f2 = lambda x : -(x - 3)**2 + 2.5*x -7.5
x = np.linspace(-2,10,100)
y = f2(x)
plt.plot(x,y)

在这里插入图片描述

# 梯度提升
# 导数函数

result = []

d2 = lambda x : -2*(x - 3) + 2.5

learning_rate = 0.1
# max_value瞎蒙的值,方法,最快的速度找到最优解(梯度下降)
# 梯度消失,梯度爆炸(因为学习率太大)
max_value = np.random.randint(2,8,size = 1)[0]
# max_value = 1000

result.append(max_value)

print('-------------------',max_value)
# 记录数据更新了,原来的值,上一步的值,退出条件
max_value_last = max_value + 0.001
# tollerence容忍度,误差,在万分之一,任务结束
# precision精确度,精度达到了万分之一,任务结束
precision = 0.0001
count = 0
while True:
    if count >3000:
        break
    if np.abs(max_value - max_value_last) < precision:
        break
#     梯度上升
    max_value_last = max_value
#     更新值:梯度上升
    max_value = max_value - learning_rate*d2(max_value)
    result.append(max_value)
    count +=1
    print('+++++++++++++++++++++%d'%(count),max_value)
print('**********************',max_value)

在这里插入图片描述

plt.figure(figsize=(12,9))
x = np.linspace(4,8,100)
y = f2(x)
plt.plot(x,y)
result = np.asarray(result)
plt.plot(result,f2(result),'*')

在这里插入图片描述

3.梯度提升用于回归

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# 回归是分类的极限思想
# 分类的类别多到一定程度,那么就是回归
from sklearn.ensemble import GradientBoostingClassifier,GradientBoostingRegressor
from sklearn import tree
# X数据:上网时间和购物金额
# y目标:14(高一),16(高三),24(大学毕业),26(工作两年)
X = np.array([[800,3],[1200,1],[1800,4],[2500,2]])
y = np.array([14,16,24,26])
# 梯度提升树用于分类,森林,集成算法,基本树(决策树,分类树)
# 使用回归,数据连续的
gbdt = GradientBoostingRegressor(n_estimators=10)
gbdt.fit(X,y)
gbdt.predict(X)
gbdt.estimators_

在这里插入图片描述
对于回归问题的提升树算法来说,若损失函数是平方损失函数,每一步只需简单拟合当前模型的残差。

# mse mean-square-error:均方误差
((y - y.mean())**2).mean()

在这里插入图片描述

((y[:2] - y[:2].mean())**2).mean()

在这里插入图片描述

# 第一颗树,根据平均值,计算了残差[-6,-4,4,6]
plt.rcParams['font.sans-serif'] = 'KaiTi'
plt.figure(figsize=(9,6))
_ = tree.plot_tree(gbdt[0,0],filled=True,feature_names=['消费','上网'])
y - y.mean()

在这里插入图片描述

#第二颗树,根据梯度提升,减小残差(残差越小,结果越好,越准确)
# learning_rate = 0.1
gbdt1 = np.array([-6,-4,6,4])
# 梯度提升 学习率0.1
gbdt1 - gbdt1*0.1

在这里插入图片描述

plt.figure(figsize=(9,6))
_ = tree.plot_tree(gbdt[1,0],filled=True,feature_names=['消费','上网'])

在这里插入图片描述

#第三颗树,根据梯度提升,减小残差(残差越小,结果越好,越准确)
gbdt2 = np.array([-5.4,-3.6,5.4,3.6])
# 梯度提升 learning_rate = 0.1
gbdt2 - gbdt2*0.1
plt.figure(figsize=(9,6))
_ = tree.plot_tree(gbdt[2,0],filled=True,feature_names=['消费','上网'])

在这里插入图片描述

#最后一颗树,预测的残差
plt.figure(figsize=(9,6))
_ = tree.plot_tree(gbdt[-1,0],filled=True,feature_names=['消费','上网'])

在这里插入图片描述

# 最后一颗树,预测的残差
nd2 = np.array([-2.325,-1.55,1.55,2.325])
# 最后一次的残差
residual = nd2 - nd2*0.1
residual
#array([-2.0925, -1.395 ,  1.395 ,  2.0925])
#根据最后一棵树的残差,计算了算法最终的预测值
y - residual
# array([16.0925, 17.395 , 22.605 , 23.9075])
#直接使用算法predict返回的值,和手算一模一样
gbdt.predict(X).round(3)
#array([16.092, 17.395, 22.605, 23.908])

4.梯度提升用于分类

在这里插入图片描述

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.ensemble import GradientBoostingClassifier
from sklearn import tree
xi = np.arange(1,11)
yi = np.array([0,0,0,1,1]*2)
display(xi,yi)

在这里插入图片描述

gbdt = GradientBoostingClassifier(n_estimators=3,max_depth=1)
gbdt.fit(xi.reshape(-1,1),yi)
gbdt.estimators_.shape
# (3, 1)

在这里插入图片描述

((yi - yi. mean())**2).mean()
# 0.24
np.var(yi)
# 0.24
# 第一颗决策树构建
plt.figure(figsize=(9,6))
_ = tree.plot_tree(gbdt[0,0],filled=True)

在这里插入图片描述
在这里插入图片描述

F0 = np.log(4/6)
F0
# -0.40546510810816444

在这里插入图片描述

# 残差,概率,负梯度
yi_1 = yi - 1/(1 + np.exp(-F0))
yi_1
 # array([-0.4, -0.4, -0.4,  0.6,  0.6, -0.4, -0.4, -0.4,  0.6,  0.6])
# 计算每个裂分点mse
mse1 = []

for i in range(1,11):
    if i == 10:
        mse1.append(np.var(yi_1))
    else:
        mse1.append((np.var(yi_1[:i])*i + np.var(yi_1[i:])*(10 - i))/10)
        
print(np.round(mse1,4))
mse1 = np.asarray(mse1)
mse1
# [0.2222 0.2    0.1714 0.225  0.24   0.2333 0.2095 0.15   0.2    0.24  ]
array([0.22222222, 0.2       , 0.17142857, 0.225     , 0.24      ,
       0.23333333, 0.20952381, 0.15      , 0.2       , 0.24      ])

在这里插入图片描述

# 两个分支,左边这个分支预测值
np.round(yi_1[:8].sum()/(((yi[:8] - yi_1[:8])*(1 - yi[:8] + yi_1[:8])).sum()),3)
# -0.625
np.round(yi_1[8:].sum()/(((yi[8:] - yi_1[8:])*(1 - yi[8:] + yi_1[8:])).sum()),3)
# 2.5
gbdt[0,0].predict(xi.reshape(-1,1))
#array([-0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625,
 #       2.5  ,  2.5  ])
 # 第一颗数据预测的值
y_1 = [-0.625]*8 + [2.5]*2
y_1 = np.asarray(y_1)
y_1 
# array([-0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625, -0.625,
 #       2.5  ,  2.5  ])

在这里插入图片描述

# 学习率 learning_rate = 0.1
F1 = F0 + y_1*0.1
F1.round(4)
# array([-0.468 , -0.468 , -0.468 , -0.468 , -0.468 , -0.468 , -0.468 ,-0.468 , -0.1555, -0.1555])
# 残差,概率,负梯度
yi_2 = yi - 1/(1 + np.exp(-F1))
yi_2.round(4)
# array([-0.3851, -0.3851, -0.3851,  0.6149,  0.6149, -0.3851, -0.3851,-0.3851,  0.5388,  0.5388])
# 拟合第二颗树
# 计算每个裂分点mse
mse2 = []

for i in range(1,11):
    if i == 10:
        mse2.append(np.var(yi_2))
    else:
        mse2.append((np.var(yi_2[:i])*i + np.var(yi_2[i:])*(10 - i))/10)
        
print(np.round(mse2,4))
mse2 = np.asarray(mse2)
# mse2
# [0.2062 0.1856 0.1592 0.2105 0.2224 0.2187 0.1998 0.15   0.1904 0.2227]
plt.figure(figsize=(9,6))
_ = tree.plot_tree(gbdt[1,0],filled=True)

在这里插入图片描述

# 两个分支,左边这个分支预测值
np.round(yi_2[:8].sum()/(((yi[:8] - yi_2[:8])*(1 - yi[:8] + yi_2[:8])).sum()),3)
# -0.571
# 两个分支,右边这个分支预测值
np.round(yi_2[8:].sum()/(((yi[8:] - yi_2[8:])*(1 - yi[8:] + yi_2[8:])).sum()),3)
# 2.168
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值