机器学习-感知机笔记(题目举例和代码解答)

1.题目


2.解答

#include<iostream>
#include<vector>
#include<string>
#include<fstream>

using namespace std;


typedef vector<double> featureVct;
typedef int label;

class Perceptron;
void printRes(Perceptron pp);

class Perceptron
{
private:
	vector<featureVct> FtSet;  //特征向量数据集
	vector<label> labelSet;   //二分类label数据集 +1或-1
	double LearnRate;		//学习率

	featureVct w;		//感知机模型参数
	double bias;		//偏置项
	int dimension;			//特征向量维度
	int count;

public:
	Perceptron(int dimension,featureVct w,double bias = 0.0,double learnRate = 1);	
	int GetCount() const;  //获取迭代次数
	const featureVct& GetW() const ;	     //获取模型参数
	void SetW(const featureVct& w);	  //设置模型参数
	double GetBias() const;			//获取偏置项
	void SetBias(double bias);		//设置骗置项
	bool ReadSource(const string& filePath); //读取数据源
	void Train();					//训练模型,得到感知机模型

public:
	double VectorDotProduct(const featureVct& f1, const featureVct& f2);  //向量点积运算)
	featureVct VectorScalarMulti(double num, const featureVct f); //向量数乘运算
	featureVct VectorAdd(const featureVct& f1, const featureVct& f2);  //向量加法运算
};

const featureVct& Perceptron::GetW() const
{
	return w;
}

void Perceptron::SetW(const featureVct& w)
{
	this->w = w;
}

double Perceptron::GetBias() const
{
	return bias;
}

void Perceptron::SetBias(double bias)
{
	this->bias = bias;
}

/*文件格式:每行表示一个样本点,特征值之间用空格隔开,最后一列存储类别信息1或-1*/
bool Perceptron::ReadSource(const string& filePath)
{
	ifstream file(filePath);
	if (!file)
		return false;
	while (!file.eof())
	{
		featureVct dataTmp;
		double tmp;
		for (int i = 0; i < dimension; ++i)
		{
			file >> tmp;
			dataTmp.push_back(tmp);
		}
		FtSet.push_back(dataTmp);
		label labelData;
		file >> labelData;
		labelSet.push_back(labelData);
	}
	return true;
}

void Perceptron::Train()
{
	//感知机训练过程
	int flag = true;
	while (flag)
	{
		for (int i = 0; i < FtSet.size(); i++)
		{
			flag = false;
			if (labelSet[i] * (VectorDotProduct(w,FtSet[i]) + bias) <= 0)
			{
				//此处的打印只是为了更直观的给大家展示学习过程,工程中最后不要直接在类中打印信息
				printRes(*this);
				flag = true;
				w = VectorAdd(w, VectorScalarMulti(labelSet[i]*LearnRate,FtSet[i]));
				bias += LearnRate * labelSet[i];
				++count;
				break;
			}
		}
		//此处的打印只是为了更直观的给大家展示学习过程,工程中最后不要直接在类中打印信息
		if(!flag)  printRes(*this);
	}

}

Perceptron::Perceptron(int dimension, featureVct w, double bias, double learnRate)
{
	this->dimension = dimension;
	this->bias = bias;
	this->LearnRate = learnRate;
	this->w = w;
	count = 0;
}

double Perceptron::VectorDotProduct(const featureVct& f1, const featureVct& f2)
{
	double sum = 0.0;
	for (int i = 0; i != f1.size(); ++i)
	{
		sum += f1[i] * f2[i];
	}
	return sum;
}

featureVct Perceptron::VectorScalarMulti(double num, const featureVct f)
{
	featureVct tmp;
	for (int i = 0; i != f.size(); ++i)
	{
		tmp.push_back(num*f[i]);
	}
	return tmp;
}

featureVct Perceptron::VectorAdd(const featureVct& f1, const featureVct& f2)
{
	featureVct tmp(0);
	for (int i = 0; i != f1.size(); ++i)
	{
		tmp.push_back(f1[i] + f2[i]);
	}
	return tmp;
}

int Perceptron::GetCount() const
{
	return count;
}

void printRes(Perceptron pp)
{
	cout << "迭代次数:" << pp.GetCount() << endl;
	cout << "w:";
	featureVct tmp = pp.GetW();

	for (int i = 0; i < tmp.size() - 1; ++i)
	{
		cout << tmp[i] << " ";
	}
	cout << tmp[tmp.size() - 1] << endl;
	cout << "bias:";
	cout << pp.GetBias() << endl;
	cout << "---------------------------" << endl;
}

int main()
{
	featureVct w;
	w.push_back(0.0); //设置w初始化参数
	w.push_back(0.0);
	Perceptron pp(2, w);  //创建特征向量为2维的感知机对象
	if (!pp.ReadSource("sun.txt"))
	{
		cout << "读取文件失败";
		exit(-1);
	}
	pp.Train();  //训练得到感知机模型
}

数据源:

3 3 1
4 3 1
1 1 -1

运行截图:


最后得到 w(1,1) b = -3

大家可能会问,这到底表示什么意思?

其实就是,得到的感知模型表达式为 f(x) = sign(x1+x2-3)      意思也就是我们得到了一条直线x+y-3 = 0 可以作为一个二类划分

注意:感知机器学习算法由于采用不同的初值或选取不同的误分类点,解可以不同


此题的详细解法描述参照《统计学习方法》赵航P45


版权声明:本文为tiankong_原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。