Adaboost

适用问题:二分类问题

  • 模型:加法模型
\[f(x)=\sum_{m=1}^{M} \alpha_{m} G_{m}(x)
\]
  • 策略:损失函数为指数函数
\[L(y,f(x))=exp[-yf(x)]
\]
  • 算法:前向分步算法
\[\left(\beta_{m}, \gamma_{m}\right)=\arg \min _{\beta, \gamma} \sum_{i=1}^{N} L\left(y_{i}, f_{m-1}\left(x_{i}\right)+\beta b\left(x_{i} ; \gamma\right)\right)
\]

特点:AdaBoost算法的特点是通过迭代每次学习一个基本分类器。每次迭代中,提高那些被前一轮分类器错误分类数据的权值,而降低那些被正确分类的数据的权值。最后,AdaBoost将基本分类器的线性组合作为强分类器,其中给分类误差率小的基本分类器以大的权值,给分类误差率大的基本分类器以小的权值。

算法步骤

1)给每个训练样本(\(x_{1},x_{2},….,x_{N}\))分配权重,初始权重\(w_{1}\)均为1/N。

2)针对带有权值的样本进行训练,得到模型\(G_m\)(初始模型为G1)。

3)计算模型\(G_m\)的误分率\(e_m=\sum_{i=1}^Nw_iI(y_i\not= G_m(x_i))\) (误分率应小于0.5,否则将预测结果翻转即可得到误分率小于0.5的分类器)

4)计算模型\(G_m\)的系数\(\alpha_m=0.5\log[(1-e_m)/e_m]\)

5)根据误分率e和当前权重向量\(w_m\)更新权重向量\(w_{m+1}\)。

6)计算组合模型\(f(x)=\sum_{m=1}^M\alpha_mG_m(x_i)\)的误分率。

7)当组合模型的误分率或迭代次数低于一定阈值,停止迭代;否则,回到步骤2)

提升树

提升树是以分类树或回归树为基本分类器的提升方法。提升树被认为是统计学习中最有效的方法之一。

提升方法:将弱可学习算法提升为强可学习算法。提升方法通过反复修改训练数据的权值分布,构建一系列基本分类器(弱分类器),并将这些基本分类器线性组合,构成一个强分类器。AdaBoost算法是提升方法的一个代表。

AdaBoost源码实现

假设弱分类器由 \(x < v\) 或 \(x > v\) 产生,阈值\(v\)使该分类器在训练集上分类误差率最低。

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
%matplotlib inline def create_data():
iris = load_iris() # 鸢尾花数据集
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
data = np.array(df.iloc[:100, [0, 1, -1]]) # 取前一百个数据,只保留前两个特征
for d in data:
if d[-1] == 0:
d[-1] = -1
return data[:, :2], data[:, -1].astype(np.int)
class AdaBoost:
def __init__(self, num_classifier, increment=0.5):
""" num_classifier: 弱分类器的数量
increment: 在特征上寻找最优切分点时,搜索时每次的增加值(数据稀疏时建议根据样本点来选择)
"""
self.num_classifier = num_classifier
self.increment = increment def fit(self, X, Y):
self._init_args(X, Y) # 逐个训练分类器
for m in range(self.num_classifier):
min_error, v_optimal, preds = float('INF'), None, None
direct_split = None
feature_idx = None # 选定的特征的列索引
# 遍历选择特征和切分点使得分类误差最小
for j in range(self.num_feature):
feature_values = self.X[:, j] # 第j个特征对应的所有取值
_ret = self._get_optimal_split(feature_values)
v_split, _direct_split, error, pred_labels = _ret if error < min_error:
min_error = error
v_optimal = v_split
preds = pred_labels
direct_split = _direct_split
feature_idx = j # 计算分类型权重alpha
alpha = self._cal_alpha(min_error)
self.alphas.append(alpha) # 记录当前分类器G(x)
self.classifiers.append((feature_idx, v_optimal, direct_split)) # 更新样本集合权值分布
self._update_weights(alpha, preds) def predict(self, x):
res = 0.0
for i in range(len(self.classifiers)):
idx, v, direct = self.classifiers[i]
# 输入弱分类器进行分类
if direct == '>':
output = 1 if x[idx] > v else -1
else: # direct == '<'
output = -1 if x[idx] > v else 1 res += self.alphas[i] * output
return 1 if res > 0 else -1 # sign(res) def score(self, X_test, Y_test):
cnt = 0
for i, x in enumerate(X_test):
if self.predict(x) == Y_test[i]:
cnt += 1
return cnt / len(X_test) def _init_args(self, X, Y):
self.X = X
self.Y = Y
self.N, self.num_feature = X.shape # N:样本数,num_feature:特征数量 # 初始时每个样本的权重均相同
self.weights = [1/self.N] * self.N # 弱分类器集合
self.classifiers = [] # 每个分类器G(x)的权重
self.alphas = [] def _update_weights(self, alpha, pred_labels):
# 计算规范化因子Z
Z = self._cal_norm_factor(alpha, pred_labels)
for i in range(self.N):
self.weights[i] = (self.weights[i] *
np.exp(-1*alpha*self.Y[i]*pred_labels[i]) / Z) def _cal_alpha(self, error):
return 0.5 * np.log((1-error)/error) def _cal_norm_factor(self, alpha, pred_labels):
return sum([self.weights[i] * np.exp(-1*alpha*self.Y[i]*pred_labels[i])
for i in range(self.N)]) def _get_optimal_split(self, feature_values):
error = float('INF') # 分类误差
pred_labels = [] # 分类结果
v_split_optimal = None # 当前特征的最优切割点
direct_split = None # 最优切割点的判别方向
max_v = max(feature_values)
min_v = min(feature_values)
num_step = (max_v - min_v + self.increment)/self.increment
for i in range(int(num_step)):
# 选取分割点
v_split = min_v + i * self.increment
judge_direct = '>'
preds = [1 if feature_values[k] > v_split else -1
for k in range(len(feature_values))] # 错误样本加权误差
weight_error = sum([self.weights[k] for k in range(self.N)
if preds[k] != self.Y[k]]) # 计算分类标签翻转后的误差
preds_inv = [-p for p in preds]
weight_error_inv = sum([self.weights[k] for k in range(self.N)
if preds_inv[k] != self.Y[k]]) # 取较小误差的判别方向作为分类器的判别方向
if weight_error_inv < weight_error:
preds = preds_inv
weight_error = weight_error_inv
judge_direct = '<' if weight_error < error:
error = weight_error
pred_labels = preds
v_split_optimal = v_split
direct_split = judge_direct return v_split_optimal, direct_split, error, pred_labels

测试模型准确率:

X, Y = create_data()

res = []
for i in range(10):
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2) clf = AdaBoost(num_classifier=50)
clf.fit(X_train, Y_train)
res.append(clf.score(X_test, Y_test))
print('My AdaBoost: {}次的平均准确率: {:.3f}'.format(len(res), sum(res)/len(res)))
My AdaBoost: 10次的平均准确率:  0.970

sklearn库的AdaBoost实例

from sklearn.ensemble import AdaBoostClassifier

res = []
for i in range(10):
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2) clf_sklearn = AdaBoostClassifier(n_estimators=50, learning_rate=0.5)
clf_sklearn.fit(X_train, Y_train)
res.append(clf_sklearn.score(X_test, Y_test))
print('sklearn AdaBoostClassifier: {}次的平均准确率: {:.3f}'.format(
len(res), sum(res)/len(res)))
sklearn AdaBoostClassifier: 10次的平均准确率:  0.945

统计学习方法——实现AdaBoost的更多相关文章

  1. Adaboost算法的一个简单实现——基于《统计学习方法(李航)》第八章

    最近阅读了李航的<统计学习方法(第二版)>,对AdaBoost算法进行了学习. 在第八章的8.1.3小节中,举了一个具体的算法计算实例.美中不足的是书上只给出了数值解,这里用代码将它实现一 ...

  2. 【NLP】基于统计学习方法角度谈谈CRF(四)

    基于统计学习方法角度谈谈CRF 作者:白宁超 2016年8月2日13:59:46 [摘要]:条件随机场用于序列标注,数据分割等自然语言处理中,表现出很好的效果.在中文分词.中文人名识别和歧义消解等任务 ...

  3. 统计学习方法 --- 感知机模型原理及c++实现

    参考博客 Liam Q博客 和李航的<统计学习方法> 感知机学习旨在求出将训练数据集进行线性划分的分类超平面,为此,导入了基于误分类的损失函数,然后利用梯度下降法对损失函数进行极小化,从而 ...

  4. 统计学习方法笔记--EM算法--三硬币例子补充

    本文,意在说明<统计学习方法>第九章EM算法的三硬币例子,公式(9.5-9.6如何而来) 下面是(公式9.5-9.8)的说明, 本人水平有限,怀着分享学习的态度发表此文,欢迎大家批评,交流 ...

  5. 统计学习方法:KNN

    作者:桂. 时间:2017-04-19  21:20:09 链接:http://www.cnblogs.com/xingshansi/p/6736385.html 声明:欢迎被转载,不过记得注明出处哦 ...

  6. 统计学习方法:罗杰斯特回归及Tensorflow入门

    作者:桂. 时间:2017-04-21  21:11:23 链接:http://www.cnblogs.com/xingshansi/p/6743780.html 前言 看到最近大家都在用Tensor ...

  7. 统计学习方法:核函数(Kernel function)

    作者:桂. 时间:2017-04-26  12:17:42 链接:http://www.cnblogs.com/xingshansi/p/6767980.html 前言 之前分析的感知机.主成分分析( ...

  8. 统计学习方法学习(四)--KNN及kd树的java实现

    K近邻法 1基本概念 K近邻法,是一种基本分类和回归规则.根据已有的训练数据集(含有标签),对于新的实例,根据其最近的k个近邻的类别,通过多数表决的方式进行预测. 2模型相关 2.1 距离的度量方式 ...

  9. 李航《统计学习方法》CH01

    CH01 统计学方法概论 前言 章节目录 统计学习 监督学习 基本概念 问题的形式化 统计学习三要素 模型 策略 算法 模型评估与模型选择 训练误差与测试误差 过拟合与模型选择 正则化与交叉验证 正则 ...

随机推荐

  1. Python基础之:数字字符串和列表

    目录 简介 数字 字符串 字符串对象str 列表 简介 Python的主要应用是进行科学计算,科学计算的基础就是数字,字符串和列表.本文将会详细的给大家介绍一下这三个数据类型的使用情况. 数字 数字是 ...

  2. Java开发工程师最新面试题库系列——Spring部分(附答案)

    Spring Spring框架是什么? 答:Spring是轻量级的面向切面和控制反转的框架.初代版本为2002年发布的interface21,Spring框架是为了解决企业级应用开发的复杂性的出现的, ...

  3. Ribbon实现负载均衡时 服务提供者注册失败 原因之一

    问题描述:提供者注册时总是不用自己配置的server.port 在project structuree中的模块总是自动添加别的模块的文件 那么一定要看看project structure中的langu ...

  4. MYSQL 悲观锁和乐观锁简单介绍及实现

    1:悲观锁 1.1 特点: 每次查询都会进行锁行,怕"其他人"进行数据的修改. 1.2 实现步骤: 步骤1:开启事务test1,并对id=2的记录进行查询,并加锁,如:   步骤2 ...

  5. s2010 安装mvc3

    下载链接如下:MVC 3安装包:http://www.microsoft.com/downloads/zh-cn/details.aspx?familyid=d2928bc1-f48c-4e95-a0 ...

  6. Git:分支管理

    代码中至少有一个分支,就是主分支master,默认都是在主分支上开发. 多分支 分支名: 版本库中必须唯一 不能以 - 开头 可以试用/,但不能以/结尾,被/分隔的名称不能以.开头 不能有连个连续的 ...

  7. AQS源码解读(ReentrankLock的公平锁和非公平锁)

    构建Debug代码: 1 package com.hl.interview.lock; 2 3 import java.util.Scanner; 4 import java.util.concurr ...

  8. Kubernetes 实战 —— 02. 开始使用 Kubernetes 和 Docker

    创建.运行及共享容器镜像 P23 运行容器 P24 运行 P24 可以运行 Docker 客户端可执行文件来执行各种 Docker 命令.例如:可以试着从 Docker Hub 的公共镜像仓库拉取.运 ...

  9. Linux下查看文件内容的几种常用命令

    [常用] 1,cat     由第一行开始显示内容,并将所有内容输出 cat的功能是将文件从第一行开始连续的将内容输出在屏幕上.但是cat并不常用,原因是当文件大,行数比较多时,屏幕无法全部容下时,只 ...

  10. MindSpore:基于本地差分隐私的 Bandit 算法

    摘要:本文将先简单介绍Bandit 问题和本地差分隐私的相关背景,然后介绍基于本地差分隐私的 Bandit 算法,最后通过一个简单的电影推荐场景来验证 LDP LinUCB 算法. Bandit问题是 ...