AdaBoost C++实现

 

   每个弱分类器的分类结果加权相加后,再用sign函数激活,得到最终分类结果。这里的权就是alpha
   alpha根据每个弱分类器的分类错误率算出,alpha = 0.5 * ln( (1-errorRate) / errorRate )

   本算法中的弱分类器为单决策树,在构建单决策树时,会根据加权错误率来衡量其性能
   被分错的样本权重高,权重计算:D[i] = D[i] * e^(-1 * alpha * label[i]) / sum(D)

   在AdaBoost训练过程中,每一次迭代都会更新D,D是AdaBoost与各弱分类器交互的地方
   每一次迭代都会创建一个弱分类器,并存储下来
   当分类错误率很小,或者迭代次数够了时,AdaBoos训练结束

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <map>
#include <math.h>
using namespace std;
 
double e = 2.718281828459;
 
double data[5][2] =   //数据集
{
	{1,   2.1},
	{2,   1.1},
	{1.3, 1},
	{1,   1},
	{2,   1}
};
 
double label[] = {1, 1, -1, -1, 1};  //标签
 
//通过阈值比较对数据分类,在阈值一边的会分到-1,另一边的会分到1
//threshIneq用于在大于、小于号之间切换,0表示小于号,1表示大于号
vector<double> stumpClassify(vector< vector<double> > &data, int dimen, double threshVal, int threshIneq)
{
	int N = data.size();
	vector<double> retLabel(N);
	if(threshIneq == 0)
	{
		for(int i=0; i<N; i++)
			if(data[i][dimen] <= threshVal)
				retLabel[i] = -1;
			else
				retLabel[i] = 1;
	}
	else 
	{
		for(int i=0; i<N; i++)
			if(data[i][dimen] > threshVal)
				retLabel[i] = -1;
			else
				retLabel[i] = 1;
	}
	return retLabel;
}
 
//单层决策树生成函数
//D为权重向量,对于分类正确的样例,权值较小,分类错误的样例,权值较大
//minError, bestClassEst为输出值,分别表示最小误差,预测结果
vector<double> buildStump(vector< vector<double> > &data,  vector<double> &D, double &minError, vector<double> &bestClassEst)
{
	int N = data.size();
	int M = data[0].size();
	int numSteps = 10;
	int i, j;
	vector<double> bestStump(3);  //存储最佳单决策树信息,分别表示特征下标、阈值、不等号
	minError = 10000000;
	for(i=0; i<M; i++)          //遍历所有特征
	{
		double rangeMin = data[0][i], rangeMax = data[0][i];
		for(j=1; j<N; j++)      //求当前特征上的最小值、最大值
		{
			if(data[j][i] < rangeMin)
				rangeMin = data[j][i];
			if(data[j][i] > rangeMax)
				rangeMax = data[j][i];
		}
		int stepSize = (rangeMax - rangeMin) / numSteps;  //步长
		for(j=-1; j<=stepSize; j++)  //阈值也可以设为取值范围之外
		{
			double threshVal = rangeMin + j * stepSize;
			for(int inequal = 0; inequal < 2; inequal++)  //在大于、小于之间切换不等式
			{
				vector<double> predictVals = stumpClassify(data, i, threshVal, inequal);  //预测结果
				double weightedError = 0;
				for(int k=0; k<N; k++)
				{
					if(predictVals[k] != label[k])
					{
						weightedError += D[k];  //计算加权错误率
					}
				}
				if(weightedError < minError)
				{
					minError = weightedError;
					bestClassEst = predictVals;
					bestStump[0] = i;
					bestStump[1] = threshVal;
					bestStump[2] = inequal;
				}
			}
		}
	}
	return bestStump;
}
 
double max(double a, double b)
{
	return a > b ? a : b;
}
 
double sign(double a)
{
	if(a > 0)
		return 1;
	else 
		return -1;
}
 
//基于单层决策树的AdaBoost训练过程
//numIt为迭代次数
vector< vector<double> > adaBoostTrainDS(vector< vector<double> > &data, int numIt)
{
	int N = data.size();
	int M = data[0].size();
	vector< vector<double> > weakClassArr;  //存储弱分类器
	vector<double> D(N);   //每个样例的权重,被分错的样例权重大
	int i, j;
	for(i=0; i<N; i++)  //初始化所有样例权重相等
		D[i] = 1.0 / (double)N;
	vector<double> aggClassEst(N);  //所有弱分类器的预测加权结果
	for(i=0; i<N; i++)
		aggClassEst[i] = 0;
	
	for(i=0; i<numIt; i++)
	{
		double error;
		vector<double> classEst;
		vector<double> bestStump = buildStump(data, D, error, classEst);         //预测
		double alpha = 0.5 * log( (1.0 - error) / max(error, 0.000001) ) / log(e);  //弱分类器的权重
		bestStump.push_back(alpha);
		weakClassArr.push_back(bestStump);  //存储弱分类器
		//为下一次迭代,计算每个样例的权重D
		double Dsum = 0;
		for(j=0; j<N; j++)
		{
			double expon = -1.0 * alpha * classEst[j] * label[j];
			D[j] *= exp(expon);
			Dsum += D[j];
		}
		double errorRate = 0;
		for(j=0; j<N; j++)
		{
			D[j] /= Dsum;
			aggClassEst[j] += alpha * classEst[j]; 
			if(sign(aggClassEst[j]) != label[j])
			{
				errorRate += 1.0;
			}
		}
		errorRate /= (double)N;
		if(errorRate == 0)
			break;
	}
	return weakClassArr;
}
 
//预测
//每个弱分类器以alpha作为权重,将弱分类器结果加权求和得到最终的结果
vector<double> adaClassify(vector< vector<double> > &test, int n, vector< vector<double> > &classifierArr)
{
	vector<double> aggClassEst(n);
	int i;
	for(i=0; i<n; i++)
		aggClassEst[i] = 0;
	for(i=0; i<classifierArr.size(); i++)
	{
		vector<double> classEst = stumpClassify(test, (int)classifierArr[i][0], classifierArr[i][1], (int)classifierArr[i][2]);
		for(int j=0; j<n; j++)
			aggClassEst[j] += classifierArr[i][3] * classEst[j];
	}
	for(i=0; i<n; i++)
		aggClassEst[i] = sign(aggClassEst[i]);
	return aggClassEst;
}
 
int main(void)
{	
	int n = 2;
	double test[2][2] = 
	{
		{5, 5},
		{0, 0}
	};
	
	int i, j;
	int N = 5, M = 2;
	cout << "数据集:" << endl;
	vector< vector<double> > d(5, vector<double>(M));
	for(i=0; i<N; i++)
	{
		for(j=0; j<M; j++)
		{
			d[i][j] = data[i][j];
			cout << d[i][j] << "\t";
		}
		cout << endl;
	}
	cout << "标签:" << endl;
	for(i=0; i<N; i++)
		cout << label[i] << endl;
 
	cout << endl << "测试数据集:" << endl;
	vector< vector<double> > t(n, vector<double>(M));
	for(i=0; i<n; i++)
	{
		for(j=0; j<M; j++)
		{
			t[i][j] = test[i][j];
			cout << t[i][j] << "\t";
		}
		cout << endl;
	}
	
	vector< vector<double> > classifierArr = adaBoostTrainDS(d, 30);
	vector<double> result = adaClassify(t, n, classifierArr);
 
	cout << "预测结果:" << endl;
	for(i=0; i<n; i++)
	{
		cout << result[i] << endl;
	}
	return 0;
}
 
 


运行结果:

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Haar分类器是一种基于Haar特征的目标检测方法。它是通过训练一个级联分类器来进行目标的识别和分类。以下是实现Haar分类器的一般步骤: 1. 数据收集:首先需要收集包含正样本和负样本的训练数据集。正样本是含有目标的图像,负样本是不含目标的图像。 2. 特征提取:通过Haar特征提取方法,从正样本和负样本中提取特征。Haar特征是基于图像局部区域的像素差值计算得出的。 3. 特征选择:从提取的Haar特征中选择一部分较为区分目标和非目标的特征。这一步通常使用Adaboost算法来进行特征选择,通过训练多个弱分类器。 4. 弱分类器训练:通过训练多个基于选择的特征的弱分类器,每个弱分类器根据特征的权重对图像进行分类。 5. 级联分类器构建:将多个弱分类器连接起来形成一个级联分类器。级联分类器的结构是由多个弱分类器按顺序排列组成,每个弱分类器的输出都通过下一个弱分类器进行检验。 6. 级联分类器训练:通过训练级联分类器,迭代地对图像进行识别和分类,直到达到所需的准确率。 7. 检测:将训练好的级联分类器应用于待检测的图像,对图像进行目标检测和分类。 总的来说,Haar分类器的实现主要包括数据收集、特征提取、特征选择、弱分类器训练、级联分类器构建、级联分类器训练和目标检测等步骤。这些步骤的顺序和具体实现方式可能会根据具体情况有所不同,但是核心思想和方法是类似的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值