大家好,我是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题
(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