18- Adaboost梯度提升树 (集成算法) (算法)

Adaboost 梯度提升树:

from sklearn.ensemble import AdaBoostClassifier
model = AdaBoostClassifier(n_estimators=500)
model.fit(X_train,y_train)


1、Adaboost算法介绍

1.1、算法引出

AI 39年(公元1995年),扁鹊成立了一家专治某疑难杂症的医院,经过半年的精心筹备,硬件设施已全部到位,只缺经验丰富的医生前来坐诊。找几个猎头打听了一下,乖乖,请一个资深专家(总监头衔的),一年的工资就得256万。这恐怕还不够去知名搜索引擎投放广告!

穷则思变,扁鹊院长想来想去,找到了两个天才的顾问,名叫Freund和Schapire,想请他们出出主意,怎样用较低的成本解决医生的问题。这两位老兄想到了同一个点子:

三个臭皮匠,赛过诸葛亮

我们玩人海战术!不如去医学院招一批应届生,给他们训练一段时间然后上岗,组成一个会诊小组,一起来给病人看病,集体决策。扁鹊很快招来了8个年轻的新手:

赵大夫,钱大夫,孙大夫,李大夫,周大夫,吴大夫,郑大夫,王大夫

1.2、算法策略

怎么训练这些新人呢?两个顾问设计出了一套培训方案:

  1. 用大量的病例让这些新手依次学习,每个大夫自己琢磨怎样诊断,学习结束后统计一下每个人在这些病例上的诊断准确率

  2. 训练时,前面的大夫误诊的病例,后面的大夫要重点学习研究,所谓查缺补漏

  3. 训练结束之后,给每个大夫打分,如果一个大夫对病例学习的越好,也就是说在这些学习的病例集上诊断的准确率越高,他在后面诊断病人时的话语权就越大

1.3、训练流程

接下来培训过程开始了。首先接受培训的是赵大夫,经过学习总结,他摸索出了一套诊断规则,这套规则表现很不错,至少在学习用的病例集上,达到了70%的诊断准确率。学习完成之后,他给每一条病例调整了权重,被他误诊的病例,权重增大,诊断正确的病例,权重调小,以便于后面的医生有重点的学习。

接下来让钱大夫学习,他同样学习这些病例,但重点要关注被赵大夫误诊的那些病例,经过一番训练,钱大夫达到了75%的准确率。学习完之后,他也调整了这些病例的权重,被他误诊的病例,加大权重,否则减小权重。

后面的过程和前面类似,依次训练孙大夫,李大夫,周大夫,吴大夫,郑大夫,王大夫,每个大夫在学习的时候重点关注被前面的大夫误诊的病例,学习完之后调整每条病例的权重。这样到最后,王大夫对前面这些大夫都误诊的病例特别擅长,专攻这些情况的疑难杂症!

1.4、大夫话语权

当所有大夫都培训完成之后,就可以让他们一起坐堂问诊了。Freund和Schapire设计出了这样一套诊断规则:来一个病人之后,8个大夫一起诊断,然后投票。如果一个大夫之前在学习时的诊断准确率为p,他在投票时的话语权是:

\bg_white \small \alpha = \frac{1}{2}ln\frac{p}{1-p}

按照这个计算规则,8个大夫的话语权为:

 1.5、诊断结果

这样诊断结果的计算方法为,先汇总整合8个大夫的诊断结果:

在这里对病人的诊断结果有两种可能,阳性和阴性,我们量化表示,+1表示阳性,-1表示阴性。

最后的诊断结果是:如果上面计算出来的s值大于0,则认为是阳性,否则为阴性。

1.6、病人诊断

第一个病人来了,8个大夫一番诊断之后,各自给出了结果:

现在是投票集体决策的时候了。投票值为:

按照规则,这个病人被判定为阳性。

1.7、算法总结

医院运营了3个月,效果出奇的好,扁鹊院长统计了一下,诊断准确率居然高达95%,不比一个资深老专家差!每个医生一年的工资10万,8个医生总共才80万,这比请一个资深专家要便宜170万,太划算了!

这次成功之后,Freund和Schapire决定把这种方法推广到其他行业,用于解决一些实际问题。这些行业要解决的问题都有一个特点:要做出一个决策,这个决策有两种可能,例如银行要根据客户的收入、负债情况、信用记录等信息决定给客户贷款还是不贷款;人脸识别公司要判断一张图像是人脸还是不是人脸。这就是机器学习中的二分类问题,给定一个样本数据,判断这个样本的类别。对于上面的疾病诊断来说,样本数据就是病人的各项检查数据,类别是阴性和阳性。

两位天才给这种方法取了一个名字:AdaBoost算法

Adaboosting中的Ada是adaptive的意思,所以AdaBoosting表示自适应增强算法

2、Adaboost算法使用

2.1、乳腺癌案例

1、导包

import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier,RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn import datasets

2、加载拆分数据

X,y = datasets.load_breast_cancer(return_X_y=True)
display(X.shape,y.shape,np.unique(y))
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2)

3、使用决策树建模

model = DecisionTreeClassifier()
# 训练
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20])
# 准确率
accuracy_score(y_test,y_pred)    # 准确率大约是:0.8947368421052632

4、使用随机森林建模

%%time
model = RandomForestClassifier(n_estimators=500)
# 训练
model.fit(X_train,y_train)
# 预测
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20])
# 准确率
accuracy_score(y_test,y_pred)   # 准确率大约是:0.956140350877193

5、使用Adaboost算法建模

%%time
model = AdaBoostClassifier(n_estimators=500)
# 训练
model.fit(X_train,y_train)
# 预测
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20])
# 准确率
accuracy_score(y_test,y_pred)  # 准确率大约是:0.9649122807017544

结论:

  • 课件,Adaboost对数据拟合更加深入,准确率高,效果好

  • 果然是:三个臭皮匠,顶个诸葛亮!

2.2、手写数字案例

1、导包

import numpy as np
import pandas as pd
from sklearn import tree
import graphviz
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier,RandomForestClassifier
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

2、加载拆分数据

data = pd.read_csv('./digits.csv')
# 随机抽样
data = data.take(np.random.randint(0,42000,5000))
X = data.iloc[:,1:]
y = data['label']
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,
                                                 random_state=1024)
display(X_train.shape,X_test.shape,y_train.shape,y_test.shape)

3、决策树

model = DecisionTreeClassifier()
# 训练
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20].values)
# 准确率
accuracy_score(y_test,y_pred)      # 准确率:0.779

4、随机森林

%%time
model = RandomForestClassifier(n_estimators=100)
# 训练
model.fit(X_train,y_train)
# 预测
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20].values)
# 准确率
accuracy_score(y_test,y_pred)     # 准确率:0.934

5、Adaboost提升算法

%%time
model = AdaBoostClassifier(n_estimators=100)
# 训练
model.fit(X_train,y_train)
# 预测
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20].values)
# 准确率
accuracy_score(y_test,y_pred)   # 准确率:0.521

6、逻辑回归算法

%%time
model = LogisticRegression(max_iter=10000)
# 训练
model.fit(X_train,y_train)
# 预测
y_pred = model.predict(X_test)
display(y_pred[:20],y_test[:20].values)
# 准确率
accuracy_score(y_test,y_pred)   # 准确率:0.891

7、可视化

plt.figure(figsize=(5*2,10*2))
plt.rcParams['font.family'] = 'STKaiti'
for i in range(50):
    plt.subplot(10,5,i + 1)
    plt.imshow(X_test.iloc[i].values.reshape(28,28))
    plt.axis('off')
    plt.title('预测值是:%d' %(y_pred[i]))

 结论:

  • 手写数字的特征是像素值,特征值多大784个

  • 而且像素中很多值都是0,没有特征区分度

  • Adaboost对这个效果就不好

  • 逻辑回归,比决策树算法效果要好一些

3、Adaboost二分类算法原理

3.1、算法流程

算法流程详解:

3.2、手撕算法

3.2.1、创建模拟数据

from sklearn.ensemble import AdaBoostClassifier
import numpy as np
from sklearn import tree
import graphviz
X = np.arange(10).reshape(-1,1)
y = np.array([1,1,1,-1,-1,-1,1,1,1,-1])
display(X,y)

3.2.2、Adaboost建模

# 使用SAMME表示在构建树时,每棵树都采用相同的分裂方式
ada = AdaBoostClassifier(algorithm='SAMME',n_estimators=3)
ada.fit(X,y)
y_ = ada.predict(X)
display(y,y_)

3.2.3、查看每一棵树结构

第一棵树:

dot_data = tree.export_graphviz(ada[0],filled=True)
graph = graphviz.Source(dot_data)
y1_ = ada[0].predict(X)  # 第一棵树的预测值,怎么预测呢?

 第二棵树:

dot_data = tree.export_graphviz(ada[1],filled=True)
print(ada[1].predict(X))
graphviz.Source(dot_data)#样本权重,发生变化了

 第三棵树:

dot_data = tree.export_graphviz(ada[2],filled=True)
print(ada[2].predict(X))
graphviz.Source(dot_data)

 3.2.4、第一棵树代码构建

1、gini系数计算

w1 = np.full(shape = 10,fill_value=1/10)
cond = y == -1
p1 = w1[cond].sum()
cond = y == 1
p2 = w1[cond].sum()
# 计算方式一
gini = p1 * (1 - p1) + p2 * (1 - p2)
print('计算方式二:',gini)
# 计算方式二
gini = 1 - p1**2 - p2**2
print('计算方式二:',gini)     # 输出:0.48

2、拆分条件

gini_result = []
best_split = {}
lower_gini = 1
# 如何划分呢,分成两部分
for i in range(len(X) - 1):
    split = X[i:i+2].mean()
    cond = (X <= split).ravel()
    part1 = y[cond]
    part2 = y[~cond]
    gini1 = 0
    gini2 = 0
    for i in np.unique(y):
        p1 = (part1 == i).sum()/part1.size
        gini1 += p1 * (1 - p1)
        p2 = (part2 == i).sum()/part2.size
        gini2 += p2 * (1 - p2)
    part1_p = cond.sum()/cond.size
    part2_p = 1 - part1_p
    gini  = part1_p * gini1 + part2_p* gini2
    gini_result.append(gini)
    if gini < lower_gini:
        lower_gini = gini
        best_split.clear()
        best_split['X[0]'] = split
print(gini_result)
print(best_split)

3、计算误差率

# 计算误差率
print(y)
y1_ = ada[0].predict(X) #预测结果
print(y1_)
y1_ = np.array([1 if X[i] < 2.5 else -1 for i in range(10)])
print(y1_)
e1 = ((y != y1_)).mean()#误差
print('第一棵树误差率是:',e1)

4、计算第一个分类器权重

# 计算第一个弱学习器的权重,相当于大夫的话语权
alpha_1 = 1/2*np.log((1 -e1)/e1 )
print('计算第一个弱学习器的权重:',alpha_1)
# 输出:计算第一个弱学习器的权重: 0.42364893019360184

5、更新样本权重

# 在w1的基础上,进行更新 w1 = [0.1,0.1,0.1……]
w2 = w1 * np.exp(-alpha_1 * y * y1_)
w2 = w2/w2.sum() # 归一化
print('第一棵树学习结束更新权重:\n',w2)
# 输出
'''
第一棵树学习结束更新权重:
 [0.07142857 0.07142857 0.07142857 0.07142857 0.07142857 0.07142857
 0.16666667 0.16666667 0.16666667 0.07142857]
'''

3.2.5、第二棵树代码构建  (后面继续)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值