Pocket_PLA算法

PLA的口袋算法,就是拿PLA训练好的Wf(从训练资料中已经不断修复好的最佳表现的权重集)和以存储的一个W作比较,如果前者很好,就替代已存储的W。

下面这个程序,前提是,现在做训练的数据是数据集的前50个样本,但是每次训练之前会用函数random_shuffle()打乱顺序,然后这种训练后比较W然后再用来测试test_data的过程重复2000次。

training_data的下载地址:https://d396qusza40orc.cloudfront.net/ntumlone%2Fhw1%2Fhw1_18_train.dat

test_data的下载地址:https://d396qusza40orc.cloudfront.net/ntumlone%2Fhw1%2Fhw1_18_test.dat

#include<fstream>  
#include<iostream>  
#include<vector>  
#include<algorithm>  
  
using namespace std;  
  
#define DEMENSION 5  //数据维度,包括特征属性x的维度和标签y 
  
//样本结构体  
struct record
{  
    double x[DEMENSION];  
    int y;  
};  
  
//读取文件数据  
void getData(fstream &datafile,vector<record> &dataset){  
    while(!datafile.eof()){  
        record curRecord;  
        curRecord.x[0] = 1;//这里初始化的值必须为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 *v1,double *v2)
{  
    int i;  
    for(i = 0; i < DEMENSION; i++) v1[i] += v2[i];  
}  
  
//计算错误率  
double getErrorRate(double *weight,vector<record> dataset){  
    int n = dataset.size();//所有的样本个数为n
	cout<<"样本个数为: "<<n<<endl;
    double errorRate= 0.0;  
    int i;  
    for(i=0;i<n;i++)  
        if(sign(multiply(weight,dataset[i].x)) != dataset[i].y)errorRate++;
	cout<<"error rate : "<<errorRate<<endl;
    return errorRate/n;  
}  
  
//口袋PLA算法,式中的iteration是迭代次数,是每次做训练的样本的个数,但是由于每次训练之前都有一个打乱样本的过程,所以每次的50个样本是不一样的 
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)//判断标签不一致,准备correct
		{  
            double temp[DEMENSION];  
            multiply(temp,trainingSet[index].x,trainingSet[index].y);  
            int i;  
            for(i=0;i<DEMENSION;i++)weights[i] += temp[i];//也可以用add(weight,temp)替代 
            if(getErrorRate(weights,trainingSet) < getErrorRate(pocketWeights,trainingSet))
			{  
                //如果修正后的权重集比口袋里的要好,则把口袋里的权重集换成这个
				int j;  
                for(j = 0;j<DEMENSION;j++)pocketWeights[j] = weights[j];   
            }  
            iter++; 
			cout<<"iter: "<<iter<<endl;
        }  
        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++ )//每次训练好的权重集去测试这个权重集在data(资料)为test_data上的表现如何(错误率多少)
	{  
        random_shuffle(trainingSet.begin(), trainingSet.end());//只取前50个样本做训练,每次都随机打乱顺序,用函数random_shuffle  
        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;  
}
最后的结果,每个计算机应该不太一样,我的是0.12364。

参考博客:http://blog.youkuaiyun.com/a1015553840/article/details/50979640

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值