基于Adaboost实现鸢尾花数据集分类

写在之前

提交内容分为两大部分:
一为Adaboost算法实现,代码在文件夹《算法实现》中,《提升方法笔记》为个人学习笔记。
二为基于Adaboost模型实现鸢尾花数据集分类,代码在《AdaBoost_iris》中。

注释:
·弱分类器只是简单的阈值判断的方法,由于鸢尾花数据集线性可分,故分类准确率非常高
·为了便于理解,代码实现了基于两个特征的分类,并做了可视化
·作业中要求基本都已实现,运行结果在《基于Adaboost的鸢尾花分类》中
·为了便于调试,需要按节运行。
·函数注释写的已经非常清晰,可以运行help 'function name’查看函数使用说明,参考内容写在了两个文档的末尾“参考”中。

一算法思想:

Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。(多个专家加权表决)。是一种重要的集成学习技术,能够将预测精度仅比随机猜度略高的弱学习器增强为预测精度高的强学习器。
在这里插入图片描述

1.样本权值:

Adaboost采用了变样本权值的方式进行学习,在每一次进行弱分类器进行学习时,首先将样本的权值分布改变。改变的依据比较容易理解,即前一个弱分类器错误分类的样本理应作为下一步需特别关注的对象,我们希望尽可能将他分对。那么怎样才能将这种“特别关注”量化呢?我理解Adaboost算法改变样本权值的做法类似于设置了一种“奖励机制”,暂且将其命名为“饼干机制”,如果上一个分错的样本,在此次样本中分对了,我们将给这次的弱分类器更多的“饼干”,(事实上Adaboost算法是一种“惩罚机制”,或者“损失机制”,期望让分类误差率更小,但本质上是一致的)那么问题落脚到了如何合理设计一个函数关系,让“饼干数”与其表现呈现一种正相关关系。Adaboost算法首先初始化时,将所有样本设置为等权重,并且满足权重和为1。(我理解这里的操作是为了之后每次迭代时,都保证权重之和是1,这样让分类误差率能够相互比较,否则,可能分类误差率为1.1和2.2可能并不能说明前者优于后者)。借助式1
在这里插入图片描述
可见,如果分类正确权值 下一步将会被压缩,( 是大于0.5的,因为弱分类器的缘故),分类错误下一步 将会被放大如此便实现了样本数据的权值分布。
在这里插入图片描述

2.弱分类器权值:

关于举手表决,最为朴素的思想是,谁可信度更高,谁理应拥有更高的发言权。那么可信度这怎么来量化呢?由于我们在之前一步将分类误差率量化成[0,1]之间的数,所以我们可以依靠分类误差率来评判哪个弱分类器更为可靠。

二算法描述:

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

在这里插入图片描述

三算法实现:

1.随机生成训练样本数据以及label,为了可视化方便起见,随机生成的样本具有两个特征。如图3-1。
在这里插入图片描述
2.对于每一维度特征,都采用阈值遍历的方式进行弱分类器判断,直到满足要求退出训练过程。(达到迭代次数或者训练误差率小于设定值)将训练中的阈值可视化如图3-2。
在这里插入图片描述
3.利用最终得到的分类器,得到估计的label与实际的label进行比较,计算测试集上的准确率如图3-3。
在这里插入图片描述
四 思考:
·明明是同一个数据集,并且采用的是遍历阈值的方法,为什么会得到不同的最佳阈值?
由于评价指标改变了,即样本数据的权值分布改变,之前分类错的样本权值变大,如果要想将该样本点分对,则需改变最佳阈值。

参考:
Adaboost入门教程——最通俗易懂的原理介绍(图文实例)
https://blog.csdn.net/px_528/article/details/72963977
统计学习方法–提升树模型(Boosting Tree)与梯度提升树(GBDT)
https://www.cnblogs.com/daguankele/p/6557328.html
在这里插入图片描述

代码

%% 样本准备
clc;close;clear;
% 生成数据与label --- 作图显示样本数据
[data, label] = Data_set(100,2);
figure(1);hold on;draw(data,label);title('训练样本');
%% 训练
figure(2);
[weakClassifier,strongClassifierLabel,m]=train(data,label,1000);
draw(data,strongClassifierLabel);hold on;title('预测数据和相应的分割线');
%% 测试
[Label] = test(weakClassifier,data,label,m);

function [data, label] = Data_set(m,n)
% 样本数据以及label生成
% 参数说明:
% m:样本数
% n:特征数
% lowT:根节点1
% highT:叶子节点数目

% 参数缺省设置----及错误检查----样本应少于总样本否则返回空
% if((m*n)>highT^2)
%     return;
% end
% 按照样本产生数据
global lowT;lowT = 0;
global highT; highT = 300;
data = zeros(m,n);
for i = 1:m 
    data(i,:) = randi([lowT, highT],1,n);% randi([50,100],5) 返回一个由介于 50100(包括二者)之间的随机整数组成的 5×5 矩阵。
end

% 分类label ∈{+1,-1}
label = 2*randi([0, 1],m,1)-1;% 随机整数

end

function draw(data,label)
% 作图
global lowT;global highT;
plot(data(label==1,1),data(label==1,2),'go','LineWidth',3,'MarkerSize',4);
plot(data(label==-1,1),data(label==-1,2),'ro','LineWidth',3,'MarkerSize',4);
xlabel('x');ylabel('y');axis([lowT highT lowT highT]);

end

function drawline(dimemsion,threshVal,step)
% 做出分割线;以及
global lowT;global highT;

% X坐标
if(dimemsion==1)
    x=threshVal*ones(1,step+1);
    y=lowT:(highT-lowT)/step:highT;
    plot(x,y,'m:','lineWidth',2);hold on;
end

% Y坐标
if(dimemsion==2)
    y=threshVal*ones(1,step+1);
    x=lowT:(highT-lowT)/step:highT;
    plot(x,y,'m:','lineWidth',2);hold on;
end

end

function [bestWeakClassifier,minEm,bestLabel]=select(data,label,D)
% 函数功能说明:
% _找到一弱分类器,使得分类误差率足够小,此分类器工作机制为硬阈值判断;
% _此弱分类器是针对某一个特征进行阈值判断
% _分类误差率是考虑被分类错误的样本,使其对应权值相加
% 
% input:
% D:为权值分布,反映了上一次弱分类器的分类情况
% bestWeakClassifier:找到的最佳阈值和最佳特征
% minEm:最小()分类误差率
% bestLabel:最佳弱分类时,所进行的估计

[m,n] = size(data);
step = m; % 阈值遍历时需要设置步长,此处设置一个与数据样本数相关的步长
bestWeakClassifier = []; % 最佳弱分类器
bestLabel = zeros(m,1);  % 最佳的估计标签
minEm = inf;            % 最小误差,初始化为无穷大
found=0;               % This is for draw the split line(threshold) of every loop

for i=1:n % 按照不同特征作为分类依据进行分类
    minvalue = min(data(:,i));
    maxvalue = max(data(:,i));
    stepValue = (maxvalue-minvalue)/step;       % 遍历时的步长
    % 遍历所有的数据取值
    for j = 0 : step % 阈值搜索的范围为[minvalue,maxvalue]
        for exchange = -1:2:1 % 阈值判断逻辑是否调换 
            threshval = minvalue + stepValue*j;
            WeakLabel = weakClassifier(data,i,threshval,exchange);
            % 错误数据为1,正确数据为0 || 计算em = Σw(误分类样本)
            errData = ones(m,1);
            errData(label == WeakLabel)=0;
            % 通过将D和勘误相乘得到加权误差
            em =D'*errData;% em = Σw(误分类样本):em:分类误差率:分类错误的样本的权值求和
            % 找到分类误差率最小的阈值(分类器)
            
            if (em<minEm) % 记录分类误差最小的分类器基于的判断特征+相应阈值+最小的误差
                found=1;
                dimemsion = i;
                thresh_temp = threshval;
                minEm = em;
                bestLabel = WeakLabel;
                bestWeakClassifier={'dimension' i;'thresh' threshval;'exchange' exchange};
            end
        end
    end
end
%  一圈画分割线(阈值)
if (found ==1)
    drawline(dimemsion,thresh_temp,step);
    found = 0;
end

end


function[Label] = test(weakClassifier,testData,testLabel,m)
% 完成对测试集的测试

num = size(testData,1);
Label = [];
for n = 1:num
    y = 0;
    for i = 0:m-1
        dimension = cell2mat(weakClassifier(i*4+1,2));
        thresh = cell2mat(weakClassifier(i*4+2,2));
        exchange = cell2mat(weakClassifier(i*4+3,2));
        alpha = cell2mat(weakClassifier(i*4+4,2));

        % 阈值逻辑判断
        if(testData(n,dimension)>thresh)
            labell = 1;
        else
            labell = -1;
        end
        labell = labell * exchange;

        y = y + alpha * labell;
    end
    y = sign(y);
    Label = [Label;y];
end
acc = sum(Label==testLabel)/size(testLabel,1);
fprintf('在测试集上,得到的准确率为%f\n',acc);
end

function [weakClassifier,strongClassifier,i] = train(data,label,numIteration)
% 参数及变量说明:
% 
% input:
% data:训练样本数据
% label:类别∈{+1,-1}
% numIteration:迭代次数
% 
% output:
% weakClassifier:一系列弱分类器
% err:错误分类率
% strongClassifier:强分类器(弱分类器的线性组合)得到的结果
%
% 
% variable:
% D:权值分布,初始化时为等权重(保证D始终是一个概率分布)
% alpha:基本分类器的系数
% bestWeakClassifier:{'dimension';'thresh';'alpha'}


m = size(data,1);
weakClassifier = {};
D = ones(m,1)/m; % 初始化为等权重
combinedWeakClassifier = zeros(m,1);

for i = 1:numIteration
    [bestWeakClassifier,minErr,bestLabel]=select(data,label,D);
    alpha= log((1-minErr)/minErr)/2;% 本次分类器对应的权重,为标量
    bestWeakClassifier(4,:) =  {'alpha' alpha};
    % 存储弱分类器参数
    weakClassifier=[weakClassifier;bestWeakClassifier];
    % 重新计算D
    D = D.*exp(-alpha*label.*bestLabel);
    D = D/sum(D);% 做归一化处理
    % 弱分类器举手表决(加权求和)
    combinedWeakClassifier = combinedWeakClassifier+alpha*bestLabel;
    % 强分类器
    strongClassifier = sign(combinedWeakClassifier);
    [~,err]=symerr(label,strongClassifier);% [number,ratio] = symerr(x,y)比较x和y。输出ratio等于错误率。
    if(err <= 0.0001)
        break;
    end
end
fprintf('训练集上准确率为:%f\n',1-err);
end
function [WeakLabel] = weakClassifier(data,dimension, threshval,exchange)  
% 函数功能:实现弱分类器(弱分类器)
% input:
% data:训练样本
% dimension:数据特征
% threshold:阈值,分类依据
% exchange:是否进行分类逻辑调换|只要低于正确率低于0.5则需要调换
%
% output:
% WeakLabel:由弱分类器进行的分类∈{+1,-1}

% 阈值判断
WeakLabel = ones(size(data,1),1);
WeakLabel(data(:,dimension)<threshval)=-1;
% 阈值判断|逻辑调换

if(exchange == -1)
    WeakLabel = -WeakLabel;
end
end

一 数据集预处理

加载鸢尾花数据集前一百个样本,包含了两类,选取前维特征信息,该数据集是线性可分的。按照比例,将一百个样本分为训练集和测试集,不失一般性,每次都乱序排列。

二 训练过程

1.在每一步中,对于每个特征都遍历一个阈值,通过阈值判断的方式进行分类,必定得到一个弱分类器(准确率大于0.5容易实现,若小于0.5,阈值判断逻辑取反即可);
2.若满足条件转4(达到预设的迭代次数,或分类误差率小于预设的允许值),否则继续执行以下操作:遍历时maintaining一个基于某维度特征的最佳阈值,其分类误差率是最小的,称之为最佳弱分类器(对于特定的一步);
3.由以上最佳弱分类器预测得到的label,计算该弱分类器的系数,以及下一步训练中样本的权值分布,回到2;
4.结束训练,得到由弱分类器加权平均的强分类器。

三 测试过程

由最终的强分类器,得到每一个弱分类器的判断依据(维度和相应的阈值),并根据判断依据得到该弱分类器估计的label,将每一个弱分类器预计的label加权平均,作为sign函数的输入,并将sign函数的输出作为最终的输出。

四 运行结果

运行结果如图,准确率为96.7%.其中蓝色点为识别错误的样例。

在这里插入图片描述
在这里插入图片描述
适当提高训练集数量,测试集准确率可达100%。如图4-3与4-4.
在这里插入图片描述

在这里插入图片描述

代码

clc;close;clear;
%% 样本初始化及可视化
[train_data,train_label,test_data,test_label,m1,n1,m2,n2] = data_init(0.5,100);
drawTrain(train_data,train_label);
%% 训练
[weakClassifier,strongClassifierLabel,m]=train(train_data,train_label,1000);
%% 测试
[Label] = test(weakClassifier,test_data,test_label,m);
drawTest(test_data,test_label,Label);
function [train_data,train_label,test_data,test_label,m1,n1,m2,n2] = data_init(k,data_num)
% 功能说明:完成数据的预处理,setosa:1  versicolor:-1
% 调用语法及参数说明:[data_iris,data_label] = data_set();
% 
load('data_iris.mat');load('data_label.mat');
data_label = zeros(data_num,1);
for i = 1:data_num
    switch species(i)
        case 'setosa'
            data_label(i) = 1;
        case 'versicolor'
            data_label(i) = -1;
    end
end
data_iris = iris(1:data_num,:);

% 乱序排列
randIndex = randperm(data_num);
data_new=data_iris(randIndex,:);
label_new=data_label(randIndex,:);

% 分为两组,比例k用于训练,剩余用于测试
k = k*data_num;
train_data=data_new(1:k,:);
train_label=label_new(1:k,:);
test_data=data_new(k+1:end,:);
test_label=label_new(k+1:end,:);
[m1,n1] = size(train_data);
[m2,n2] = size(test_data);


end

function drawTest(test_data,test_label,Label)
% 测试集及误分类样本可视化

figure(2);hold on
plot(test_data(test_label==1,1),test_data(test_label==1,2),'go','LineWidth',3,'MarkerSize',4);
plot(test_data(test_label==-1,1),test_data(test_label==-1,2),'ro','LineWidth',3,'MarkerSize',4);
plot(test_data(test_label~=Label,1),test_data(test_label~=Label,2),'bo','LineWidth',3,'MarkerSize',4);
xlabel('x');ylabel('y');
title('测试集及误分类样本可视化');

end

function drawTrain(data,label)
% 训练集数据可视化

figure(1);hold on
plot(data(label==1,1),data(label==1,2),'go','LineWidth',3,'MarkerSize',4);
plot(data(label==-1,1),data(label==-1,2),'ro','LineWidth',3,'MarkerSize',4);
xlabel('x');ylabel('y');
title('训练样本');

end

function [bestWeakClassifier, minEm, bestLabel]=select(data,label,D)
% 函数功能说明:
% _找到一弱分类器,使得分类误差率足够小,此分类器工作机制为硬阈值判断;
% _此弱分类器是针对某一个特征进行阈值判断
% _分类误差率是考虑被分类错误的样本,使其对应权值相加
% 
% input:
% D:为权值分布,反映了上一次弱分类器的分类情况
% bestWeakClassifier:找到的最佳阈值和最佳特征
% minEm:最小()分类误差率
% bestLabel:最佳弱分类时,所进行的估计

[m,n] = size(data);
step = 10*m; % 阈值遍历时需要设置步长,此处设置一个与数据样本数相关的步长
bestWeakClassifier = []; % 最佳弱分类器
bestLabel = zeros(m,1);  % 最佳的估计标签
minEm = inf;            % 最小误差,初始化为无穷大

for i=1:n % 按照不同特征作为分类依据进行分类
    minvalue = min(data(:,i));
    maxvalue = max(data(:,i));
    stepValue = (maxvalue-minvalue)/step;       % 遍历时的步长
    % 遍历所有的数据取值
    for j = 0 : step % 阈值搜索的范围为[minvalue,maxvalue]
        for exchange = -1:2:1 % 阈值判断逻辑是否调换 
            threshval = minvalue + stepValue*j;
            WeakLabel = weakClassifier(data,i,threshval,exchange);
            % 错误数据为1,正确数据为0 || 计算em = Σw(误分类样本)
            errData = ones(m,1);
            errData(label == WeakLabel)=0;
            % 通过将D和勘误相乘得到加权误差
            em =D'*errData;% em = Σw(误分类样本):em:分类误差率:分类错误的样本的权值求和
            % 找到分类误差率最小的阈值(分类器)
            if (em<minEm) % 记录分类误差最小的分类器基于的判断特征+相应阈值+最小的误差
                minEm = em;
                bestLabel = WeakLabel;
                bestWeakClassifier={'dimension' i;'thresh' threshval;'exchange' exchange};
            end
        end
    end
end
end

function[Label] = test(weakClassifier,testData,testLabel,m)
% 完成对测试集的测试

num = size(testData,1);
Label = [];
for n = 1:num
    y = 0;
    for i = 0:m-1
        dimension = cell2mat(weakClassifier(i*4+1,2));
        thresh = cell2mat(weakClassifier(i*4+2,2));
        exchange = cell2mat(weakClassifier(i*4+3,2));
        alpha = cell2mat(weakClassifier(i*4+4,2));

        % 阈值逻辑判断
        if(testData(n,dimension)>thresh)
            labell = 1;
        else
            labell = -1;
        end
        labell = labell * exchange;

        y = y + alpha * labell;
    end
    y = sign(y);
    Label = [Label;y];
end
acc = sum(Label==testLabel)/size(testLabel,1);
fprintf('在测试集上准确率为%f\n',acc);
end

function [weakClassifier,strongClassifier,i] = train(data,label,numIteration)
% 参数及变量说明:
% 
% input:
% data:训练样本数据
% label:类别∈{+1,-1}
% numIteration:迭代次数
% 
% output:
% weakClassifier:一系列弱分类器
% err:错误分类率
% strongClassifier:强分类器(弱分类器的线性组合)得到的结果
%
% 
% variable:
% D:权值分布,初始化时为等权重(保证D始终是一个概率分布)
% alpha:基本分类器的系数
% bestWeakClassifier:{'dimension';'thresh';'alpha'}


m = size(data,1);
weakClassifier = {};
D = ones(m,1)/m; % 初始化为等权重
combinedWeakClassifier = zeros(m,1);

for i = 1:numIteration
    [bestWeakClassifier,minErr,bestLabel]=select(data,label,D);
    alpha= log((1-minErr)/minErr)/2;% 本次分类器对应的权重,为标量
    bestWeakClassifier(4,:) =  {'alpha' alpha};
    % 存储弱分类器参数
    weakClassifier=[weakClassifier;bestWeakClassifier];
    % 重新计算D
    D = D.*exp(-alpha*label.*bestLabel);
    D = D/sum(D);% 做归一化处理
    % 弱分类器举手表决(加权求和)
    combinedWeakClassifier = combinedWeakClassifier+alpha*bestLabel;
    % 强分类器
    strongClassifier = sign(combinedWeakClassifier);
    [~,err]=symerr(label,strongClassifier);% [number,ratio] = symerr(x,y)比较x和y。输出ratio等于错误率。
    if(err <= 0.0001)
        break;
    end
end
fprintf('训练集上准确率为:%f\n',1-err);
end

function [WeakLabel] = weakClassifier(data,dimension,threshval,exchange)  
% 函数功能:实现弱分类器(弱分类器)
% input:
% data:训练样本
% dimension:数据特征
% threshval:阈值,分类依据
% exchange:是否进行分类逻辑调换|只要低于正确率低于0.5则需要调换
%
% output:
% WeakLabel:由弱分类器进行的分类∈{+1,-1}

% 阈值判断
WeakLabel = ones(size(data,1),1);
WeakLabel(data(:,dimension)<threshval)=-1;
% 阈值判断|逻辑调换

if(exchange == -1)
    WeakLabel = -WeakLabel;
end
end
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值