機器學習基石 (Machine Learning Foundations) 作业1 Q18-20的C++实现(pocket)

        大家好,我是Mac Jiang,今天和大家分享Coursera---台湾大学---機器學習基石 (Machine Learning Foundations)---作业1:Q18-20的C++实现。虽然我的代码得到了较为正确的结果,但是肯定不是最好的,如果各位博友有更好的实现思路,请留言指正,谢谢!希望我的博客能给您带来一些学习上的帮助!Q15-17的实现过程已经在:http://blog.csdn.net/a1015553840/article/details/50979434中给出,有需要的博友可以前往阅读。

        虽然已经有很多博友给出了这个算法的Phython实现过程,说实话,利用Phython的实现比C++来的简答,但是不是每位博友都会Phython,所以在这里提供C++的实现过程,以备各位博友的不时之需!


        好的,话不多说。这次主要任务是实现PLA的pocket过程,前面博客提到,当训练样本是线性可分的,我们用PLA可以很快的实现样本的分类。但是如果样本不是线性可分的,那么我们就需要对PLA进行改进。这里采用的是贪心算法,他的思想是把当前最好的分类线保存在口袋中,然后对曲线进行修正得到新的线。如果得到新的线对训练样本的错误率更小,那么我们把这条线保存下来。继续运行程序,直到达到足够的迭代次数。

0.初始化口袋曲线w

{

    1.寻找分类错误点(x,y)

    2.修正错误:w(t+1) = w(t) + y*x

    3.如果w(t+1)对训练样本的错误率比口袋里的w更小,则用w(t+1)替代w

}until(达到足够的迭代次数)


        如果知道训练样本D是线性可分的,则运行PLA比较好,应为PLA速度快(不用判断对所有样本的错误率)

        如果训练样本不是线性可分的(绝大多数情况),则运行pocket,但是pocket得运行速度慢


1.第18题

機器學習基石 (Machine Learning Foundations) 作业1 Q18-20的C++实现(pocket)_第1张图片

(1)题意:首先分别从题目中写的两个网址中下载训练样本和测试样本,然后运行pocket算法,每次迭代50次,共运行2000次,计算他对测试样本的平均错误率

(2)实现:

#include<fstream>
#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

#define DEMENSION 5  //数据维度

//样本结构体
struct record{
	double x[DEMENSION];
	int y;
};

//读取文件数据
void getData(fstream &datafile,vector<record> &dataset){
	while(!datafile.eof()){
		record curRecord;
		curRecord.x[0] = 1;
		int i;
		for(i=1 ; i<DEMENSION ; i++)datafile>>curRecord.x[i];
		datafile>>curRecord.y;
		dataset.push_back(curRecord);
	}
	datafile.close();
}

//计算sign值
int sign(double x){
	if(x <= 0)return -1;
	else return 1;
}

//计算两个向量内积,判断是否需要修正
double multiply(double *v1, double *v2){
	int i;
	double temp = 0.0;
	for(i = 0; i < DEMENSION; i++)temp += v1[i] * v2[i];
	return temp;
}

//函数重载,计算向量v与整数num的积,用于计算y*x(y为+1或-1,x为向量)
void multiply(double *result,double *v,int num){
	int i;
	for(i = 0; i < DEMENSION; i++)result[i] =  num * v[i];
}

//计算两向量的和放入result中,用于计算w(i+1)=w(i)+y*x
void add(double *result,double *v1,double *v2){
	int i;
	for(i = 0; i < DEMENSION; i++)result[i] = v1[i] + v2[i];
}

//计算错误率
double getErrorRate(double *weight,vector<record> dataset){
	int n = dataset.size();
	double errorRate= 0.0;
	int i;
	for(i=0;i<n;i++)
		if(sign(multiply(weight,dataset[i].x)) != dataset[i].y)errorRate++;
	return errorRate/n;
}

//口袋PLA算法
void pocketPLA(double *pocketWeights,double *weights,vector<record> trainingSet,int iteration){
	int index = 0;
	int iter= 1;
	int n = trainingSet.size();
	while(iter < iteration){
		if(sign(multiply(trainingSet[index].x,weights)) != trainingSet[index].y){
			double temp[DEMENSION];
			multiply(temp,trainingSet[index].x,trainingSet[index].y);
			int i;
			for(i=0;i<DEMENSION;i++)weights[i] += temp[i];
	    	if(getErrorRate(weights,trainingSet) < getErrorRate(pocketWeights,trainingSet)){
				int j;
				for(j = 0;j<DEMENSION;j++)pocketWeights[j] = weights[j]; 
			}
			iter++;
		}
		if(index == n-1)index = 0;
		else index++;
	}
}

void main(){
	vector<record> trainingSet;
	vector<record> testSet;
	fstream datafile1("training_data.txt");
	fstream datafile2("test_data.txt");
	if(datafile1.is_open()&&datafile2.is_open()){
		getData(datafile1,trainingSet);
		getData(datafile2,testSet);
	}
	else{
		cout<<"can not open file!"<<endl;
		exit(1);
	}
	double weights[DEMENSION],pocketWeights[DEMENSION];
	
	double ave_error = 0.0 ;
	int j;
	for(j = 0; j < 2000; j++ ){

		random_shuffle(trainingSet.begin(), trainingSet.end());

		int i;
		for(i=0;i<DEMENSION;i++){  //注意,这里需要初始化!!!不初始化值会乱码,程序出错!!!
		    weights[i]=0.0;
		    pocketWeights[i]=0.0;
		}
		pocketPLA(pocketWeights,weights,trainingSet,50);
	    double trainingError = getErrorRate(pocketWeights,trainingSet);
   	    double testError = getErrorRate(pocketWeights,testSet);
		ave_error += testError;
		cout<<"第"<<j<<"次实验---"<<"training error:"<<trainingError<<" test error:"<<testError<<endl;

	}
	cout<<"average error rate:"<<ave_error/2000<<endl;
}

(3)实验结果:个人的计算机计算出来为0.132011


2.第19题

(1)题意:如果不采用贪心算法,而是采用第50次迭代结果为最终曲线,运行2000次,求对测试样本的平均错误率

(2)分析:很简单,只要把pocketPLA函数中

	if(getErrorRate(weights,trainingSet) < getErrorRate(pocketWeights,trainingSet)){
				int j;
				for(j = 0;j<DEMENSION;j++)pocketWeights[j] = weights[j]; 
			}

这个if判断去掉就可以了

(3)答案:个人计算机结果为0.271567


3.第19题

(1)题意:如果把每次调用口袋算法的迭代次数从50次调为100次,求对测试样本的平均错误率

(2)分析:这个更简单,我写的pocketPLA函数有个参数iteration这个就是迭代次数,在main调用时,把pocketPLA(pocketWeights,weights,trainingSet,50)的50改为100就可以了。由于迭代次数增加,所以错误率应该比18中的错误率小一些。

(3)答案:个人计算机得到的结果为0.114024


from:http://blog.csdn.net/a1015553840/article/details/50979640

你可能感兴趣的:(learning,machine,pocket,C++实现,PLA,fou,機器學習基石,Q18-20)