機器學習基石(Machine Learning Foundations) 机器学习基石 作业三 Q18-20 C++实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a1015553840/article/details/51085835

        大家好,我是Mac Jiang,今天和大家分享Coursera-NTU-機器學習基石(Machine Learning Foundations)-作业三 Q18-20的C++实现。虽然有很多大神已经在很多博客中给出了Phython的实现,但是给出C++实现的文章明显较少,这里为大家提供一条C++实现的思路!我的代码虽然能够得到正确答案,但是其中可能有某些思想或者细节是错误的,如果各位博友发现,请及时留言纠正,谢谢!再次声明,博主提供实现代码的原因不是为了让各位通过测试,而是为学习有困难的同学提供一条解决思路,希望我的文章对您的学习有一些帮助!

本文出处:http://blog.csdn.net/a1015553840/article/details/51085835

其他问题解答请看汇总帖:http://blog.csdn.net/a1015553840/article/details/51085129


        这部分内容讲的主要是利用梯度下降发实现逻辑回归。

(1)逻辑回归

        逻辑回归Hyphothesis:

        逻辑回归单个点错误:

        逻辑回归总代价:

(2)梯度下降法

        逻辑回归的batch gradient descent:

        逻辑回归的stostic gradient descent:不需要N个样本求平均了,直接取其中一个的梯度

(3)逻辑回归的实现步骤

        


1.第十八题

(1)题意:分别从两个网站中下载训练样本和测试样本用于做逻辑回归。取迭代步长ita = 0.001,迭代次数T=2000,求Eout

(2)实现:注意,这里实现总w的初始化最好全为0,因为最优解的X就在0附近。由于T=2000只迭代了2000次太少了,如果初始化别的数如全为1,那么2000次迭代后是找不到最优解的,至少要迭代的几万次!题目中没有给出默认初始化w值,但是我试出来是初始化全为0。 这也说明逻辑回归迭代几千次都不小数目,要得到比较好的解需要几万次,或者采用高级优化的梯度下降法。

#include "stdafx.h"
#include<iostream>
#include<fstream>
#include<vector>

using namespace std;

#define DEMENSION 20//数据维度

struct Record{  //数据格式
	double x[DEMENSION+1];
	int y;
};

struct Weight{  //参数格式
	double w[DEMENSION+1];
};

int sign(double x){  //sign
	if(x > 0)return 1;
	else return -1;
}

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

double sigmoid(double x){  //sigmoid函数,逻辑函数,s形函数
	return 1.0 / (1.0 + exp(-x));
}

double vectorMul(double *a,double *b,int demension){ //两个向量相乘返回内积
	double temp = 0.0;
	for(int i = 0; i <demension; i++)
		temp += a[i] * b[i];
	return temp;
}

void calcuBatchGradient(vector<Record> &data,Weight weight,int N,double *grad){  //批量梯度下降法
	for(int i = 0; i < N; i++){
		double temp = sigmoid(-1 * vectorMul(weight.w,data[i].x,DEMENSION+1) * (double)data[i].y);
		for(int j = 0; j <= DEMENSION; j++)
			grad[j] += -1.0 * temp * data[i].x[j] * data[i].y; 
	}
	for(int i = 0; i <= DEMENSION; i++)
		grad[i] = grad[i] / N;
}

void calcuStochasticGradient(Record data,Weight weight,double *grad){  //随机梯度下降法
	double temp = sigmoid(-1 * vectorMul(weight.w,data.x,DEMENSION+1) * (double)data.y);
	for(int j = 0; j <= DEMENSION; j++)
		grad[j] += -1.0 * temp * data.x[j] * data.y;

}

void updateW(Weight &weight,double ita,double *grad){  //利用得到的梯度更新参数weight
	for(int i = 0; i <= DEMENSION; i++){
		weight.w[i] = weight.w[i] - (ita * grad[i]);
	}
}

double calcuLGError(vector<Record> &data,Weight weight,int N){ //计算逻辑回归的错误计算方法计算错误
	double error = 0.0;
	for(int i = 0; i < N; i++){
		error += log(1 + exp(-data[i].y * vectorMul(weight.w,data[i].x,DEMENSION+1)));
	}
	return double(error / N);
}

void logisticRegression(vector<Record> &data,Weight &weight,int N,double ita,int iteration){  //逻辑回归
    for(int i = 0; i < iteration; i++){     //利用batch梯度下降法计算逻辑回归
		double grad[DEMENSION+1] = {0.0};
		calcuBatchGradient(data,weight,N,grad);
		updateW(weight,ita,grad);
		cout<<"iter = "<<i<<",训练样本的逻辑回归错误Ein = "<<calcuLGError(data,weight,N)<<endl;
	}
	/*int i = 0;   //利用Stochastic梯度下降法计算逻辑回归
	while(i < iteration){
		double grad[DEMENSION+1] = {0.0};
		calcuStochasticGradient(data[i%N],weight,grad);
		updateW(weight,ita,grad);
		cout<<"iter = "<<i<<",训练样本的逻辑回归错误Ein = "<<calcuLGError(data,weight,N)<<endl;
		i++;
	}*/
}

double calcuError(vector<Record> &data,Weight weight,int N){  //利用逻辑回归做二元分类,计算0/1错误
	double error = 0.0;
	for(int i = 0; i < N; i++){
		if(sign(vectorMul(data[i].x,weight.w,DEMENSION+1)) != data[i].y)
			error++;
	}
	return double(error / N);
}

void main(){
	vector<Record> trainingData;  //训练样本
	vector<Record> testData;      //测试样本
	fstream file1("trainingData.txt");//读取训练样本数据
	fstream file2("testData.txt");//读取测试样本数据
	if(file1.is_open() && file2.is_open()){
		getData(file1,trainingData);
		getData(file2,testData);
	}
	else{
		cout<<"can not open file!"<<endl;
		exit(1);
	}
	int train_N = trainingData.size();//训练样本个数
	int test_N = testData.size();//测试样本个数
	double ita = 0.001;//步长ita
	int interation = 2000;//迭代次数
	Weight weight;//逻辑回归参数
	for(int i = 0; i <= DEMENSION; i++)//参数初始化为0;注意,这里要是全为1迭代2000次是得不到结果的,因为最优解在0附近;要想得到结果iteration必须在几万次次左右
		weight.w[i] = 1;
	logisticRegression(trainingData,weight,train_N,ita,interation);
	cout<<"训练样本的0/1错误Ein = "<<calcuError(trainingData,weight,train_N)<<endl;
    cout<<"测试样本的0/1错误Eout = "<<calcuError(testData,weight,test_N)<<endl;
}

(3)答案:0.475


2.第十九题

(1)题意:把第18题的步长ita=0.001改为0.01,求Eout

(2)分析:这个更简单,只要把main函数里的ita改为0.01就可以了

(3)答案:迭代后Ein = 0.195 ,Eout = 0.22;    如果迭代20000次的话,Ein=0.172,Eout=0.182此时就基本达到局部最优了!

                   答案为0.220


3.第二十题

(1)题意:ita取0.001,迭代2000次,利用随机梯度下降法(Stostic Gradieng Descent),求迭代2000次后的Eout

(2)分析:我在18题给出的程序中已经写出了随机梯度下降的计算方法!第18题用的是batch gradient descent,只要在logisticRegression这个函数中,把上面的注释掉,把下面注释中的代码拿出来就是随机梯度下降法的逻辑回归实现了。

(3)答案:a.迭代2000次,Ein=0.466,Eout = 0.475,所以答案是0.475

                    b.如果迭代20000次,Ein=0.186,Eout=0.196,所以说2000次太少了!需要几万次才能达到最优解

               对于这道题而言,由于T=2000,答案为0.475


本文出处:http://blog.csdn.net/a1015553840/article/details/51085835

其他问题解答请看汇总帖:http://blog.csdn.net/a1015553840/article/details/51085129





猜你喜欢

转载自blog.csdn.net/a1015553840/article/details/51085835
今日推荐