监督算法大比拼之BP、SVM、adaboost非线性多分类实验

写在之前:

前些文章曾经细数过从决策树、贝叶斯算法等一些简单的算法到神经网络(BP)、支持向量机(SVM)、adaboost等一些较为复杂的机器学习算法(对其中感兴趣的朋友可以往前的博客看看),各种算法各有优缺点,基本上都能处理线性与非线性样本集,然通观这些算法来看,个人感觉对于数据(无论线性还是非线性)的分类上来说,里面比较好的当数BP、SVM、adaboost元算法这三种了,由于前面在介绍相应算法原理以及实验的时候所用的样本以及分类情况都是二分类的,对于多分类的情况未曾涉及过,而实际情况往往是分类多分类数据的样本较多,本节旨在对BP、SVM、adaboost这三种个人感觉较好的算法进行一个对比,同时实验一个简单的非线性多分类样本

一:理解与分析

既然是多分类样本,首先对样本需要理解,所谓多分类就是样本集中不止2类样本,至少3类才称得上是多分类。比如下面一个二维非线性的多类样本集(这也是后面我们实验的样本集):

每种颜色代表一类,可以看到共有5类,同时也可以看到是一个非线性的吧,这里可以就把五类分别设置为1~5类类标签。

好了,曾经在单个算法介绍的时候,里面的实验都是二分类的(也就是只有上述5类样本中的两类),二分类的方式很简单,不是你就是我的这种模式,那么从二分类到多分类该怎么转换呢?假如一个样本不是我,那也可能不是你呀,可能是他它她对吧,这个时候该如何呢?

现在一般的方式都是将多分类问题转化为二分类问题,因为前面许多算法在原理推导上都是假设样本是二分类的,像SVM,整个推导过程以至结论都是相对二分类的,根本没有考虑多分类,依次你想将SVM直接应用于多分类是不可能的,除非你在从原理上去考虑多分类的情况,然后得到一个一般的公式,最后在用程序实现这样才可以。

那么多分类问题怎么转化为二分类问题?很简单,一个简单的思想就是分主次,采取投票机制。转化的方式有两种,因为分类问题最终需要训练产生一个分类器,产生这个分类器靠的是训练样本,前面的二分类问题实际上就是产生了一个分类器,而多分类问题根据训练集产生的可不止是一个分类器,而是多个分类器。

第一种方式就是将训练样本集中的某一类当成一类,其他的所有类当成另外一类,像上面的5类,我把最中间的一类当成是第一类,并重新赋予类标签为1,而把四周的四类都认为是第二类,并重新赋予类标签维-1,好了现在的问题是不是就是二分类问题了?是的。那二分类好办,用之前的任何一个算法处理即可。好了,这是把最中间的当成一类的情况下建立的一个分类器。同理,我们是不是也可以把四周任何一类自成一类,而把其他的统称为一类呀?当然可以,这样依次类推,我们共建立了几个分类器?像上面5类就建立了5个分类器吧,好了到了这我们该怎么划分测试集的样本属于哪一类了?注意测试集是假设不知道类标签的,那么来了一个测试样本,我把它依次输入到上述建立的5个分类器中,看看最终它属于哪一类的多,那它就属于哪一类了吧。比如假设一个测试样本本来是属于中间的(假设为第5类吧),那么先输入第五类自成一类的情况,这个时候发现它属于第五类,记录一下5,然后再输入左上角(假设为1类)自成一类的情况,那么发现这个样本时不属于1类的,而是属于2,3,4,5这几类合并在一起的一类中,那么它属于2,3,4,5中的谁呢?都有可能吧,那么我都记一下,此时记一下2,3,4,5。好了再到有上角,此时又可以记一下这个样本输入1,3,4,5.依次类推,最后把这5个分类器都走一遍,就记了好多1~5的标签吧,然后去统计他们的数量,比如这里统计1类,发现出现了3次,2,3,4都出现了3次,就5出现了5次,那么我们就有理由认为这个样本属于第五类,那么现在想想是不是就把多类问题解决了呢?而这个过程参考这位大神博客中的一张图表示就如下:

可以看到,其实黑实线本类是我们想要的理想分类面,而按照这种方式建立的分类面是带阴影部分的那个分类面,那阴影部分里面表示什么呢?我们想想,假设一个样本落在了阴影里面,比如我画的那个紫色的点,按照上面计算,发现它属于三角形一类的2次,属于正方形一类的2次,属于圆形一类的1次,那这个时候你怎么办?没招,只能在最大的两次中挑一个,运气好的认为属于三角形,挑对了,运气不好的挑了个正方形,分错了。所以阴影部分是属于模棱两可的情况,这个时候只能挑其中一个了。

这是第一种方式,那还有第二种分类方式,思想类似,也是转化为二分类问题,不过实现上不同。前面我们是挑一类自成一类,剩下的所有自成一类,而这里,也是从中挑一类自成一类,然剩下的并不是自成一类,而是在挑一类自成一类,也就是说从训练样本中挑其中的两类来产生一个分类器。像上述的5类,我先把1,2,类的训练样本挑出来,训练一个属于1,2,类的分类器,然后把1,3,挑出来训练一个分类器,再1,4再1,5再2,3,等等(注意2,1与1,2一样的,所以省去了),那这样5类样本需要建立多少个分类器呢?n*(n-1)/2吧,这里就是5*4/2=10个分类器,可以看到比上面的5个分类器多了5个。而且n越大,多的就越多。好了建立完分类器,剩下的问题同样采取投票机制,来一个样本,带到1,2建立的发现属于1,属于1类的累加器加一下,带到1,3建立的发现也属于1,在加一下,等等等等。最后看看5个类的累加器哪个最大就属于哪一类。那么一个问题来了,会不会出现像上面那种情况,有两个或者更多个累加器的值是一样的呢?答案是有的,但是这种情况下,出现一样的概率可比上述情况的概率小多了(比较是10个分类器来的结果,怎么也得比你5个的要好吧),同样一个示意图如下:

可以看到重叠部分就是中间那么一小块,相比上面那种方式小了不少吧。

那么细比较这两种方式,其实各有优缺点。第一种方式由于建立的分类器少(n越大越明显吧,两者相差(n*(n-1)/2 - n)个分类器)。也就是在运算的时候速度更快,而第二种方式虽然速度慢,但是精度高呀,而且现在计算机的速度也够快了,可以弥补第二种方式的缺点,所以个人更倾向于第二种方式了。

好了说完了理论部分,实践起来吧,实践是检验真理的唯一方法

二:BP模式识别工具箱处理多分类实验

首先采用神经网络算法来实验,同时为了速度与准确率,我们实验matlab的神经网络工具箱,关于该工具箱怎么用,请参考:

机器学习之实战matlab神经网络工具箱

为了实现较好的效果,这里我们直接使用matlab在BP下建立起来的模式识别工具箱(nprtool)。该工具箱的使用可以通过GUI界面直接操作,也可以命令操作,需要说明一点的就是数据的输入形式,尤其是对于类标签的设置,在该工具箱下,类标签已经不再是用数字1~5直接表示,而是用一个向量,比如类别1可以表示为[1,0,0,0,0],类别3可以表示为[0,0,1,0,0]这种表示方式。同时如果样本输入每一行表示一个样本,那么类别就得像上面那一,每一行表示一个样本类别。如果每一列为一个样本,那么对应的标签也是每一列一个样本,下面实验每一列表示一个样本的样本集:

%%
% * matlab模式识别工具箱的分类设计
% * 多类非线性分类
%
%%
clc
clear
close all
%% Load data
% * 数据预处理
data = load(‘data_test.mat‘);
data = data.data;
%选择训练样本个数
num_train = 200;%共500个样本
%构造随机选择序列
choose = randperm(length(data));
train_data = data(choose(1:num_train),:);
label_temp = train_data(:,end);
label_train = zeros(length(train_data),5);
%把输出分类标签改为工具箱要求的格式
for i = 1:length(train_data)
    label_train(i,label_temp(i)) = 1;
end
train_data = train_data(:,1:end-1)‘;
label_train = label_train‘;
%
test_data = data(choose(num_train+1:end),:);
label_temp = test_data(:,end);
label_test = zeros(length(test_data),5);
%把输出分类标签改为工具箱要求的格式
for i = 1:length(test_data)
    label_test(i,label_temp(i)) = 1;
end
test_data = test_data(:,1:end-1)‘;
label_test = label_test‘;
%%
% Create a Pattern Recognition Network
hiddenLayerSize = 10;
net = patternnet(hiddenLayerSize);
% 将训练集再按比例内分为训练集、验证集、测试集
net.divideParam.trainRatio = 70/100;
net.divideParam.valRatio = 15/100;
net.divideParam.testRatio = 15/100;
% Train the Network
[net,tr] = train(net,train_data,label_train);
% Test the Network
predict = net(test_data);
[~,predict] = max(predict);
%% show the result --testings
figure;
gscatter(test_data(1,:),test_data(2,:),predict);
[~,label_test] = max(label_test);
accuracy = length(find(predict==label_test))/length(test_data);
title([‘predict the testing data and the accuracy is :‘,num2str(accuracy)]);

可以看到,其实程序开头许多对数据进行了训练样本与测试样本的选择,同时对类标签进行了变化。之间部分是建立模式识别的神经网络网路系统,最后应用这个网络对测试集进行测试,得到一个结果如下:

这是中间出来的网路结构:

可以看到,这是200个训练样本300个测试样本下的结果,该工具箱产生的准确率是相当高的。

其实对于该工具箱也可以通过GUI界面直接操作,不用编写那么多代码,但是你的输入数据格式什么的都得提前转换对才行。直接命令输入nprtool就可以打开该工具箱的GUI,详细的可以自行研究。

三:svm之libsvm处理多分类实验

下面我们来通过svm方法进行上述数据的分类。由于上面的BP部分直接采用工具箱函数,并没有涉及到前面我们说的两种由二分类到多分类的方法,对于svm我们将把两种方式都演示一遍。这里我会用到libsvm工具箱,关于该工具箱怎么使用请看:

解密SVM系列(五):matlab下libsvm的简单使用

第一种:

%%
% * libsvm工具箱实验
% * 多类非线性分类
%
%%
clc
clear
close all
%% Load data
% * 数据预处理--分两类情况
data = load(‘data_test.mat‘);
data = data.data;
%选择训练样本个数
num_train = 200;
%构造随机选择序列
choose = randperm(length(data));
train_data = data(choose(1:num_train),:);
gscatter(train_data(:,1),train_data(:,2),train_data(:,3));
label_train = train_data(:,end);
test_data = data(choose(num_train+1:end),:);
label_test = test_data(:,end);
%% svm的构建与训练
for i = 1:5 %5类
    %重新归类
    label_temp = label_train;
    index1 = find(label_train == i);
    index2 = find(label_train ~= i);
    label_temp(index1) = 1;
    label_temp(index2) = -1;
    % 训练模型
    model{i} = svmtrain(label_temp,train_data(:,1:end-1),‘-t 2‘);
end
% 用模型来预测测试集的分类
predict = zeros(length(test_data),1);
for i = 1:length(test_data)
    data_test = test_data(i,:);
    addnum = zeros(1,5);
    for j = 1:5
        temp = svmpredict(1,data_test(:,1:end-1),model{j});
        if temp > 0
            addnum(j) = addnum(j) + 1;
        else
            addnum = addnum + 1;
            addnum(j) = addnum(j) - 1;
        end
    end
    [~,predict(i)] = max(addnum);
end
%% show the result--testing
figure;
gscatter(test_data(:,1),test_data(:,2),predict);
accuracy = length(find(predict==label_test))/length(test_data);
title([‘predict the training data and the accuracy is :‘,num2str(accuracy)]);

结果如下:

下面进行第二种方式:

%%
% * libsvm工具箱实验
% * 多类非线性分类
%
%%
clc
clear
close all
%% Load data
% * 数据预处理
data = load(‘data_test.mat‘);
data = data.data;
%选择训练样本个数
num_train = 200;
%构造随机选择序列
choose = randperm(length(data));
train_data = data(choose(1:num_train),:);
gscatter(train_data(:,1),train_data(:,2),train_data(:,3));
label_train = train_data(:,end);
test_data = data(choose(num_train+1:end),:);
label_test = test_data(:,end);
%% svm的构建与训练
num = 0;
for i = 1:5-1 %5类
    for j = i+1:5
        num = num + 1;
        %重新归类
        index1 = find(label_train == i);
        index2 = find(label_train == j);
        label_temp = zeros((length(index1)+length(index2)),1);
        %svm需要将分类标签设置为1与-1
        label_temp(1:length(index1)) = 1;
        label_temp(length(index1)+1:length(index1)+length(index2)) = -1;
        train_temp = [train_data(index1,:);train_data(index2,:)];
        % 训练模型
        model{num} = svmtrain(label_temp,train_temp(:,1:end-1),‘-t 2‘);
    end
end
% 用模型来预测测试集的分类
predict = zeros(length(test_data),1);
for i = 1:length(test_data)
    data_test = test_data(i,:);
    num = 0;
    addnum = zeros(1,5);
    for j = 1:5-1
        for k = j+1:5
            num = num + 1;
            temp = svmpredict(1,data_test(:,1:end-1),model{num});
            if temp > 0
                addnum(j) = addnum(j) + 1;
            else
                addnum(k) = addnum(k) + 1;
            end
        end
    end
    [~,predict(i)] = max(addnum);
end
%% show the result--testing
figure;
gscatter(test_data(:,1),test_data(:,2),predict);
accuracy = length(find(predict==label_test))/length(test_data);
title([‘predict the testing data and the accuracy is :‘,num2str(accuracy)]);

结果如下:

可以看到的是这两种方式下的结果都挺好,准确率都高,由于训练样本随机选择,每一次的结果不会一样。至于哪一种好,我觉得,当样本大的时候,在速度满足要求的情况下,并且数据可能重叠的时候,第二种是好些的。

四:adaboost元算法处理多分类实验

关于adaboost元算法的详细原理与实现过程请看上节:

机器学习之白话与实战adaboost元算法

考虑到adaboost元算法并没有去找相应的软件工具箱,所以这里就用自己编写的函数来实现吧,在上述博客中涉及到了下面会使用到的两个子函数buildSimpleStump和adaBoostTrainDs,限于篇幅,这里不再贴出来,要使用的朋友可以自行把那里的拷贝过来。

那么在基于上述的两个子函数下,我们在编写两个函数,一个是adaboost的训练函数,一个是adaboost的预测函数,函数如下:

训练函数:

function model = adaboost_train(label,data,iter)
[model.dim,model.direction,model.thresh,model.alpha] = ...
    adaBoostTrainDs(data,label,iter);
model.iter = iter;

预测函数:

function predict = adaboost_predict(data,model)
h = zeros(model.iter,1);
for j = 1:model.iter
    if model.direction(j) == -1
        if data(model.dim(j)) <= model.thresh(j)
            h(j) = -1;
        else
            h(j) = 1;
        end
    elseif model.direction(j) == 1
        if data(model.dim(j)) <= model.thresh(j)
            h(j) = 1;
        else
            h(j) = -1;
        end
    end
end
predict = sign(model.alpha‘*h);

有了这两个函数我们就可以进行实验了,这里我们只一第二种方式的多分类为例,函数同上面的svm类似,只不过把那里的训练模型函数与预测函数改到我们这里的这种,主函数如下:

%%
% * adaboost
% * 多类非线性分类
%
%%
clc
clear
close all
%% Load data
% * 数据预处理
data = load(‘data_test.mat‘);
data = data.data;
%选择训练样本个数
num_train = 200;
%构造随机选择序列
choose = randperm(length(data));
train_data = data(choose(1:num_train),:);
gscatter(train_data(:,1),train_data(:,2),train_data(:,3));
label_train = train_data(:,end);
test_data = data(choose(num_train+1:end),:);
label_test = test_data(:,end);
%% adaboost的构建与训练
num = 0;
iter = 30;%规定弱分类器的个数
for i = 1:5-1 %5类
    for j = i+1:5
        num = num + 1;
        %重新归类
        index1 = find(label_train == i);
        index2 = find(label_train == j);
        label_temp = zeros((length(index1)+length(index2)),1);
        %svm需要将分类标签设置为1与-1
        label_temp(1:length(index1)) = 1;
        label_temp(length(index1)+1:length(index1)+length(index2)) = -1;
        train_temp = [train_data(index1,:);train_data(index2,:)];
        % 训练模型
        model{num} = adaboost_train(label_temp,train_temp,iter);
    end
end
% 用模型来预测测试集的分类
predict = zeros(length(test_data),1);
for i = 1:length(test_data)
    data_test = test_data(i,:);
    num = 0;
    addnum = zeros(1,5);
    for j = 1:5-1
        for k = j+1:5
            num = num + 1;
            temp = adaboost_predict(data_test,model{num});
            if temp > 0
                addnum(j) = addnum(j) + 1;
            else
                addnum(k) = addnum(k) + 1;
            end
        end
    end
    [~,predict(i)] = max(addnum);
end
%% show the result--testing
figure;
gscatter(test_data(:,1),test_data(:,2),predict);
accuracy = length(find(predict==label_test))/length(test_data);
title([‘predict the testing data and the accuracy is :‘,num2str(accuracy)]);

这还是在200个训练样本下300个测试样本的一个结果如下:

可以看到在iter=30个弱分类器下的结果已经是高的惊人了。

至此上述三种方法介绍完毕,上述三种方法对于监督式的多分类问题来说确实都相当好了。只要根据你的样本来调节适当参数,感觉总是可以得到较好的结果的。叙述了这么多,喜欢的朋友顶一下吧~_~!同时也欢迎相互交流。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 12:27:45

监督算法大比拼之BP、SVM、adaboost非线性多分类实验的相关文章

支持向量机(SVM)非线性数据分割

1.目标 本指导中你将学到: l  当不可能线性分割训练数据时,怎样定义SVM最优化问题: l  在这种问题上,怎样配置CvSVMParams中的参数满足你的SVM: 2.动机 为什么我们有兴趣扩展SVM最优化问题来处理非线性分割训练数据?SVM在计算机视觉应用中需要一个比线性分类器更加强有力的工具.原因在于,事实上,在这种问题上训练数据几乎不能被一个超平面分割开.考虑一个这种任务,例如,面部识别.这种情况下,训练数据由图像上的一组面部数据和非面部(任何除面部以外的其他东西)数据组成.这些训练数

【机器学习算法-python实现】svm支持向量机(2)—简化版SMO算法

(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景知识 通过上一节我们通过引入拉格朗日乗子得到支持向量机变形公式.详细变法可以参考这位大神的博客--地址 参照拉格朗日公式F(x1,x2,...λ)=f(x1,x2,...)-λg(x1,x2...).我们把上面的式子变型为: 约束条件就变成了: 下面就根据最小优化算法SMO(Sequential Minimal Optimization).找出距离分隔面最近的点,也就是支持向量集.如下图的蓝色点所示.

[机器学习之SVM] 线性SVM还是非线性SVM?【转】

SVM的应用领域很广,分类.回归.密度估计.聚类等,但我觉得最成功的还是在分类这一块. 用于分类问题时,SVM可供选择的参数并不多,惩罚参数C,核函数及其参数选择.对于一个应用,是选择线性核,还是多项式核,还是高斯核?还是有一些规则的. 实际应用中,多数情况是特征维数非常高.如OCR中的汉字识别,提取8方向梯度直方图特征,归一化的字符被等分成8*8的网格,每个网格计算出长度为8的方向直方图,特征维数是8*8*8 = 512维.在这样的高维空间中,想把两个字符类分开,用线性SVM是轻而易举的事,当

简单易学的机器学习算法——神经网络之BP神经网络

一.BP神经网络的概念 BP神经网络是一种多层的前馈神经网络,其基本的特点是:信号是前向传播的,而误差是反向传播的.详细来说.对于例如以下的仅仅含一个隐层的神经网络模型: (三层BP神经网络模型) BP神经网络的过程主要分为两个阶段.第一阶段是信号的前向传播,从输入层经过隐含层.最后到达输出层:第二阶段是误差的反向传播,从输出层到隐含层.最后到输入层,依次调节隐含层到输出层的权重和偏置,输入层到隐含层的权重和偏置. 二.BP神经网络的流程 在知道了BP神经网络的特点后,我们须要根据信号的前向传播

数据挖掘算法学习(八)Adaboost

本文不定期更新.原创文章,转载请注明出处,谢谢. Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器).Adaboost算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值.将修改过权值的新数据集送给下层分类器进行训练,最后将每次得到的分类器最后融合起来,作为最后的决策分类器. 算法概述 1.先通过对N个训练样本的学习得

【机器学习算法-python实现】svm支持向量机(3)—核函数

(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景知识 前面我们提到的数据集都是线性可分的,这样我们可以用SMO等方法找到支持向量的集合.然而当我们遇到线性不可分的数据集时候,是不是svm就不起作用了呢?这里用到了一种方法叫做核函数,它将低维度的数据转换成高纬度的从而实现线性可分. 可能有的人不明白为什么低维度的数据集转换成高维度的就可以实现线性可分,下面摘抄一个网上的例子解释一下.看下面这个图,我们设红色的区域是一组数据 ,而直线ab除了红色区域以

无监督算法

无监督算法: KMeans算法: 1. 随机初始化数据集簇的中心,一般从数据集中选择 2. 外循环: 内循环:计算各个数值点到中心的距离,进行聚类 计算每个聚类的平局值,移动聚类中心 PCA算法: 目标:数据压缩和可视化 1. 对样本数据进行去均值和归一化 2. 组建sigma矩阵,然后进行奇异值分解,求的压缩和的结果Z 异常检测算法: 1. 选择可能适应于异常样本的特征 2. 根据样本得到高斯分布的均值和方差 3. 对给定的样本计算其是否为异常样本 异常检测与监督学习: 异常检测:正样本数量较

【机器学习算法-python实现】K-means无监督学习实现分类

1.背景 无监督学习的定义就不多说了,不懂得可以google.因为项目需要,需要进行无监督的分类学习. K-means里面的K指的是将数据分成的份数,基本上用的就是算距离的方法. 大致的思路就是给定一个矩阵,假设K的值是2,也就是分成两个部分,那么我们首先确定两个质心.一开始是找矩阵每一列的最大值max,最小值min,算出range=max-min,然后设质心就是min+range*random.之后在逐渐递归跟进,其实要想明白还是要跟一遍代码,自己每一步都输出一下看看跟自己想象的是否一样. (

车辆追踪算法大PK:SVM+HOGvs.YOLO

介绍 对于Udacity(优达学城)自动驾驶汽车纳米学位的汽车检测和跟踪项目,如果使用传统的计算机可视化技术将是一个挑战,就像方向梯度直方图(Histogram of Oriented Gradients,HOG)和其它特征组合在一起在视频里跟踪汽车一样,理想的解决方案应该是实时运行的,如>30FPS,我曾经使用线性SVM来处理视频,在一台i7 CPU计算机上得到的结果只有可怜的3FPS.最后我使用YOLO来处理视频终于通过了Udacity的项目,YOLO是一个超快的用于对象检测的卷积神经网络,