参考之前的博文,AdaBoost算法学习实现的c++代码
//adaboost.h
#ifndef ADABOOST_H
#define ADABOOST_H
#include<cmath>
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
#define FEATURETYPE double
struct FeaVec
{
unsigned int dim;
std::vector<FEATURETYPE>fea;
int label;//这里只去两个值,-1,1
FeaVec(unsigned int d) :dim(d)
{
}
};
class weakclassfier;
class adaboost
{
public:
friend class weakclassfier;
adaboost();
virtual ~adaboost();
void train();
int classify(FeaVec data);
void load_trainset(vector<FeaVec>*data);
protected:
private:
double*W;
int dim;//特征维数
std::vector<FeaVec>trainset;
std::vector<weakclassfier*>classfier;
double aggri_error;
};
#endif // ADABOOST_H
//adaboost.cpp
#include "stdafx.h"
#include "adaboost.h"
class weakclassfier
{
public:
friend class adaboost;
weakclassfier(adaboost*ada)
{
this->ada = ada;
min_error_rate = 1000000;
}
void build();
std::vector<int>* stumpclassify(int const k, double const threshold,
vector<FeaVec>& data, bool greatthan);
~weakclassfier();
private:
bool greaterthan;//控制不等式符号
int dim;//当前分类器在那一维进行分类
double threshold;
double min_error_rate;//当前弱分类器在训练集上的错误率
std::vector<int>*predicted;//保存对训练集的分类结果
double alpha;//在强分类器中所占的权重
adaboost* ada;
};
weakclassfier::~weakclassfier()
{
if (predicted != NULL)
delete predicted;
}
void weakclassfier::build()
{
double minerror = 100000;
for (int i = 0; i < ada->dim; i++)//外循环次数少
{
double min = 100000;
double max = -100000;
for (int j = 0; j<ada->trainset.size(); j++)
{
if (ada->trainset[j].fea[i]>max)
max = ada->trainset[j].fea[i];
if (ada->trainset[j].fea[i] < min)
min = ada->trainset[j].fea[i];
}
double step = (max - min) / double(10);
for (double j = min; j < max;)
{
j += step;
double current_error = 0;
bool flag = false;
vector<int>*aa = stumpclassify(i, j, ada->trainset, true);
for (int k = 0; k < ada->trainset.size(); k++)
current_error += ((*aa)[k] != ada->trainset[k].label) ? ada->W[k] : 0;
if (current_error < min_error_rate)
{
min_error_rate = current_error;
threshold = j;
greaterthan = true;
dim = i;
if (predicted != NULL)
delete predicted;
predicted = aa;
flag = true;
}
current_error = 0;
aa = stumpclassify(i, j, ada->trainset, false);
for (int k = 0; k < ada->trainset.size(); k++)
current_error += ((*aa)[k] != ada->trainset[k].label) ? ada->W[k] : 0;
//current_error += abs((*aa)[k] -ada->trainset[k].label) *ada->W[k];
if (current_error < min_error_rate)
{
min_error_rate = current_error;
threshold = j;
greaterthan = false;
dim = i;
if (predicted != NULL)
delete predicted;
predicted = aa;
flag = true;
}
if (!flag)//new和delete必须配套使用
delete aa;
}
}
assert(min_error_rate < 0.5);
}
std::vector<int>* weakclassfier::stumpclassify(int const k, double const threshold,
vector<FeaVec>&data, bool greatthan)
{
std::vector<int>*pre = new vector < int > ;
//开始假设都满足大于阈值
//开始假设都满足小于阈值
(*pre).insert((*pre).begin(), data.size(), 1);
for (int j = 0; j < data.size(); j++)
{
if (greatthan&&data[j].fea[k] < threshold)//对于greater_than,ada->trainset[j]被预测为另一个类
{
(*pre)[j] = -1;
}
else if (!greatthan&&data[j].fea[k] > threshold)
{
(*pre)[j] = -1;
}
}
return pre;
}
adaboost::adaboost()
{
}
adaboost::~adaboost()
{
for (int i = 0; i < classfier.size(); i++)
delete classfier[i];
if (W != NULL)
delete[]W;
}
void adaboost::train()
{
W = new double[trainset.size()];
//全部初始化为0,用memset可以,但某一特定值,只能用循环了
//memset(W, double(1) / double(trainset.size()), trainset.size()*sizeof(double));
for (int i = 0; i < trainset.size(); i++)
W[i] = double(1) / double(trainset.size());
vector<double> aggrigate;
aggrigate.resize(trainset.size());
while (classfier.size() < 4)
{
aggri_error = 0;
weakclassfier*weak = new weakclassfier(this);
weak->build();
if (weak->min_error_rate < 0.5)
{
//弱分类器的准确率越高,其权重也越大
weak->alpha = (0.5*log((1.0 - weak->min_error_rate) / (weak->min_error_rate + 1e-16)));
classfier.push_back(weak);
double sumW = 0;
for (int j = 0; j < trainset.size(); j++)
{
//根据当前弱分类器分类结果将错分样本的权重提升
W[j] *= exp(weak->alpha*((*weak->predicted)[j] == trainset[j].label ? -1 : 1));
sumW += W[j];
}
for (int j = 0; j < trainset.size(); j++)
{
W[j] /= (sumW + 0.00000001);
// aggrigate[j] += weak->alpha*(*weak->predicted)[j];
//aggri_error += ((aggrigate[j] > 0) ? 1 : -1) == trainset[j].label ? 0 : 1;
}
//aggri_error /= double(trainset.size());
// if (aggri_error == 0)
// break;
}
delete weak->predicted;
}
}
int adaboost::classify(FeaVec data)
{
vector<FeaVec>bb;
bb.push_back(data);
double cc = 0;
for (int i = 0; i < classfier.size(); i++)
{
vector<int>*aa = classfier[i]->stumpclassify(classfier[i]->dim,
classfier[i]->threshold, bb, classfier[i]->greaterthan);
// for (int j = 0; j < data.dim; j++)
cc += (*aa)[0] * classfier[i]->alpha;
delete aa;
}
return cc > 0 ? 1 : -1;
}
void adaboost::load_trainset(vector<FeaVec>*data)
{
trainset = *data;
dim = data->back().dim;
}
//main
#include "stdafx.h"
#include"adaboost.h"
int _tmain(int argc, _TCHAR* argv[])
{
cout << double(1) / double(5) << endl;
FeaVec aa(2), bb(2), cc(2), dd(2),ee(2);
aa.fea.push_back(2);
aa.fea.push_back(1.1);
aa.label = 1;
bb.fea.push_back(1.3);
bb.fea.push_back(1.0);
bb.label = -1;
cc.fea.push_back(1.0);
cc.fea.push_back(1.0);
cc.label = -1;
dd.fea.push_back(2);
dd.fea.push_back(1.0);
dd.label = 1;
ee.fea.push_back(1);
ee.fea.push_back(2.1);
ee.label = 1;
vector<FeaVec>pp;
pp.push_back(aa);
pp.push_back(bb);
pp.push_back(cc);
pp.push_back(dd);
pp.push_back(ee);
adaboost ada;
ada.load_trainset(&pp);
ada.train();
FeaVec ff(2);
ff.fea.push_back(0.9);
ff.fea.push_back(1.1);
int a = ada.classify(ff);
return 0;
}