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

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

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

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


1第十三题

(1)题意:给定的target fuction的表达式如上图所示,他是用一个圆圈做二元分类。我们的工作是在X=[-1,1]x[-1,1]上随机产生1000个点,利用f(x1,x2)计算它的值,然后在基础上添加10%的噪声(二元分类的噪声就是把10%的样本的y值取相反数)。如果不做feacher transform 直接利用数据做线性回归,利用得到的参数做线性分类器,问此事得到的Ein是多少。运行1000次取平均值。

(2)分析:首先要随机产生训练样本并添加噪声,对于C++如何随机产生随机样本和噪声我们以前的代码中就已经说过了,这里不再重复。

                    其次,我们要利用训练样本计算线性回归。

                    最后,我们用得到的线性回归参数w作为二元分类器的参数,计算sign(w*x)得到预测值,计算他与y的0/1错误,得到错误率EiN

                    提示:由于线性回归需要用到求pseudo-inverse的操作,这里要求逆矩阵,这里要是自己写逆矩阵的算法比较复杂,可以直接调用已经写好的C++库。比较常用的C++库有eigen,cuda等等,本人用的是eigen。如果你嫌复杂,可以直接使用Matlab实现本题,操作会简单的多。

                    对于eigen的用法有很多前人已经写过,比较好的链接有:http://blog.csdn.net/augusdi/article/details/12907341.其实我们用到的只是其中的一些很基础的操作,最重要的是求逆矩阵和求广义逆矩阵的操作,大家不妨看看。

                    对于第13题的代码和第14题的很像,只要把第14题的featureTransform操作去掉就可以了,所以这里不再附上。

(3)答案:0.5


2.第十四题

(1)题意:在第13题,直接利用逻辑回归做分类是很不理想的,错误率为50%,没有实际意义。但是我们可以先进行特征转换,正确率就会高很多。特征转化的操作也很简单,上课老师都说过,这里就不再累述。

(2)分析:具体的代码实现如下。其中,(Xtest,ytest)是第15题才需要进行的操作,为了简洁都写在一起了。

#include "stdafx.h"
#include<iostream>
#include<Eigen/Eigen>//C++下的一个常用的矩阵运算库
using namespace Eigen;
using namespace std;

#define X1min  -1 //定义第一维度的最大最小值
#define X1max  1
#define X2min  -1//定义第二维度的最大最小值
#define X2max 1
#define N 1000//定义样本数


int sign(double x){

	if(x <= 0)return -1;
	else return 1;
}

void getRandData(Matrix<double,N,3> &X,Matrix<double,N,1> &y){ //在(X1min,X1max)x(X2min,X2max)区间初始化点
	for(int i = 0; i < N; i++){
		X(i,0) = 1.0;
		X(i,1) = double(X1max - X1min) * rand()/RAND_MAX - (X1max - X1min)/2.0;
		X(i,2) = double(X2max - X2min) * rand()/RAND_MAX - (X2max - X2min)/2.0;
		y(i,0) = sign(X(i,1)*X(i,1) + X(i,2)*X(i,2) - 0.6);
	}
}

void getNoise(Matrix<double,N,3> &X,Matrix<double,N,1> &y){//加入噪声
	for(int i =0; i < N; i++)
		if(rand()/RAND_MAX < 0.1)
			y(i,0) = - y(i,0);
}

void transform(Matrix<double,N,3> &X,Matrix<double,N,6> &Z){//将X空间转换为Z空间
	for(int i = 0; i < N; i++){
		Z(i,0) = 1;
		Z(i,1) = X(i,1);
		Z(i,2) = X(i,2);
		Z(i,3) = X(i,1) * X(i,2);
		Z(i,4) = X(i,1) * X(i,1);
		Z(i,5) = X(i,2) * X(i,2);
	}
}

void linearRegression(Matrix<double,N,6> &Z,Matrix<double,N,1> &y,Matrix<double,6,1> &weight){//逻辑回归计算,得参数weight
	weight = (Z.transpose() *Z).inverse() * Z.transpose() * y;
}

double calcuE(Matrix<double,N,6> &Z,Matrix<double,N,1> &y,Matrix<double,6,1> &weight){//计算E_in
	double E_in = 0.0;
	Matrix<double,N,1> temp = Z * weight;
	for(int i = 0; i < N; i++)
		if((double)sign(temp(i,0)) != y(i,0))
			E_in++;
	return double(E_in/N);
}


void main(){
	int seed[1000];//种子
	double total_Ein = 0.0;
	double total_Eout = 0.0;
	Matrix<double,N,3> X;//X组成的矩阵
	Matrix<double,N,3> Xtest;//测试样本
	Matrix<double,N,6> Z;//Z组成矩阵
	Matrix<double,N,6> Ztest;//测试样本
	Matrix<double,N,1> y;//y组成的向量
	Matrix<double,N,1> ytest;//测试样本
	Matrix<double,6,1> weight;//参数weight
	Matrix<double,6,1> totalWeight;
	totalWeight<<0,0,0,0,0,0;

	for(int i = 0; i < N; i++)//进行1000次,每次需要1个种子,所以先利用rand初始化种子
		seed[i] = rand();
	for(int k =0; k < N; k++){
		srand(seed[k]);//每次取一个种子进行试验
		getRandData(X,y);//得到随机样本
		getNoise(X,y);//添加噪声
		getRandData(Xtest,ytest);
		getNoise(Xtest,ytest);
		transform(X,Z);
		transform(Xtest,Ztest);
		linearRegression(Z,y,weight);//线性回归计算参数weight
		total_Ein += calcuE(Z,y,weight);//计算每次E_in错误和
		total_Eout += calcuE(Ztest,ytest,weight);
		totalWeight += weight;
		cout<<"k="<<k<<",Ein = "<<calcuE(Z,y,weight)<<",Eout = "<<calcuE(Ztest,ytest,weight)<<endl;
	}
	cout<<"Average E_in:"<<total_Ein / 1000.0<<endl;
	cout<<"Average E_out:"<<total_Eout / 1000.0<<endl;
	cout<<totalWeight/1000;
	

}

(3)答案:最后一项。其实用脑子想想就知道是最后一个,应为f(x1,x2)=sign(x1^2+x2^2-0.6)是一个圆,那么得到的肯定也差不多是个圆。加上噪声可以与原来的圆稍微偏离一些,但不会太过分。


15.第十五题


(1)题意:在14题得到的最优w的基础上,我们利用产生训练样本的方法一样产生1000个测试样本,计算误差。重复1000次求平均

(2)实现:已经在14题给出

Average E_in:训练样本平均误差

Average E_out:测试样本平均误差

最下面的六行数据是第14题的w的六个参数

(3)答案:0.1


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



猜你喜欢

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