感知器及其C++的实现

来源:互联网 发布:淘宝网首页官网床垫 编辑:程序博客网 时间:2024/06/06 18:21

本来计划这篇博客写如何用web前端写2048,但是鉴于以前的代码写得太乱,暂时并不打算继续这个话题了;

本篇的主题是“感知器及其C++的实现”,我会简单介绍模式识别中的感知器是个什么东西,并且会给出我写的C++代码


进入正题:

什么是感知器?

引出:
比如说某银行的分析软件有这样一项功能,通过输入某客户的个人信息(年龄、性别、职业、收入、欠债情况、信用情况等),返回是否给该客户提供信用卡服务;对于这个问题,我们可以定义某个函数f可以完成这样的功能,但是这个f是未知的;但是通过很多先验数据(已经通过人工判定是否发放行用卡),我们可以估计出这样一个函数g(宏观上来说就和人一样,当你对于某个事件见得多了,下次你就能预见其可能状态了),它能够做出和f相似的判定;这就是数据驱动。

其中此例子的数据是指:通过人工判定是否发放信用卡的数据,称之为是带有标签的。


对于是否发放信用卡此类问题,只有两种结果:发或不发;对于这样的,只有两种状态的问题,我们可以用一个线性感知器来完成。


怎么操作呢?

首先我们做一个转换,将数据都转换成可以计算的量,不妨都装换为数字,比如有一个这样的用户jerry,其用户数据如下

{

yearsold: 20, //年龄

salary: 10000, //月收入

debt:100000 //欠债

}

可能客户不同的信息在是否发放信用卡这件事上占有不同的比重,那么我们可以给每条数据的每个信息加上一个比重w求和(加权求和)。则可以得出一个总的权重:

y = yearsold * w1 + salary * w2 + debt * w3;

容易想到,可以设定一个阈值(threshold)判定是否发放信用卡,则做如下假设:

yearsold * w1 + salary * w2 + debt * w3 > threshold,则发放信用卡

yearsold * w1 + salary * w2 + debt * w3 < threshold,则不发放信用卡

再把这个式子转化为yearsold * w1 + salary * w2 + debt * w3 + (-1)*threshold ? 0;其中?表示">" 或 “<”

习惯用矩阵或者向量形式表示:(w1, w2, w3, threshold)·(yearsold, salary, debt, -1) ? 0,可以用符号函数在形式上简化函数:g(x) = sign((w1, w2, w3, threshold)·(yearsold, salary, debt, -1) );其中x表示输入的数据,是一个一维或者多维数据;且记w = (w1, w2, w3, threshold) 。


现在开始,似乎已经有某种方法得出一系列权重的来判定是否发放信用卡了。当时,到底怎么来获取这些权重呢?如何才能讲我有的数据都用上呢?

有一种迭代的方式(怎么来的我也不知道,但是这种方法确实能够将所有数据都用上,并且加入新的数据时不用全部重新计算,或许你能够提出新的方法):

w(n+1) = w(n) + f(n)x(n), 当g(n)≠f(n)的时候用这个式子更新w,否则w不变(因为此时的w对x(n)已经能够正确区分了)

其中w(n)表示第n次迭代的w, f(n)表示第n条数据的标签(发不发行用卡可以用-1(不发) 和 +1(发)表示),x(n)表示第n条数据;


但是这样有一个问题,什么时候停止迭代呢?遍历完所有数据吗?这样似乎不太好,因为遍历完所有数据也不能保证w是好的。可以这样做:

1、设置一个迭代上限,如果在此迭代上限内能够正确区分所有数据,则停止迭代,否则一直迭代,知道迭代次数达到上限;

2、看相邻两次w所带来的误差,如果两次误差变化不大,则说明已经不能够再优化w(这个是模仿计算方法提出的,不一定可行,且需要提出一个误差的计算函数)

如果数据时线性可分的,用线性分类器可以得到好的结果,如果线性不可分则不能直接得到好的结果。

到此为止,线性感知器的介绍就结束了。


接下来是代码部分:

#pragma once#include <iostream>#include <vector>class PLA{public:std::vector<double> _w;int _dataSum,_wSum;bool _pokeFlag;unsigned long int _pokeErrors;unsigned long int _pokePos;PLA(int, double);PLA();PLA(std::vector< std::vector<double> >, double);~PLA();void InitVectorW(int, double);void LoadMark(std::vector<int>);bool LoadData(std::vector< std::vector<double> >);bool Train(unsigned long int);private:std::vector< std::vector<double> > _data;protected:std::vector<double> _singleData;std::vector<int> _markVector;int _mark;int _index;bool Perce(int, int);bool ReadNextData();};


#include "PLA.h"#include "Vector.h"PLA::PLA(){_index = 0;_dataSum = 0;_wSum = 0;}PLA::PLA(int len, double init){_index = 0;_dataSum = 0;_wSum = 0;for (int i = 0; i < len + 1; i++)_w.push_back(init);_wSum = len + 1;}PLA::PLA(std::vector< std::vector<double> > data, double init){_index = 0;int dataSum = data.size();if (dataSum){int len = data[0].size();for (int i = 0; i < len + 1; i++)_w.push_back(init);LoadVector(data, _data);_wSum = len + 1;_dataSum = dataSum;}elsereturn;}PLA::~PLA(){}bool PLA::Perce(int part1, int part2){using namespace std;double ans = VectorMul(_singleData, _w);//std::cout << ans << std::endl;int flagTemp = (ans >= 0) ? part1 : part2;bool flag = ((flagTemp) == _mark) ? true : false;//cout << flagTemp << "  " << _mark << endl;if (!flag){//std::cout << flagTemp << "   " << _mark << std::endl;//cout << "!!" << endl;VectorAdd(_w, _singleData, _mark);//int i;//for (i = 0; i < _w.size(); i++)//{//_w[i] += _singleData[i] * _mark;//}return false;}return true;}void PLA::InitVectorW(int len, double init){for (int i = 0; i < len + 1; i++)_w.push_back(init);_wSum = len + 1;}bool PLA::LoadData(std::vector< std::vector<double> > data){int dataSum = data.size();if (dataSum){int len = data[0].size();LoadVector(data, _data);_wSum = len + 1 ;_dataSum = dataSum;return true;}elsereturn false;}void PLA::LoadMark(std::vector<int> markVector){for (int i = 0; i < markVector.size(); i++)_markVector.push_back(markVector[i]);}bool PLA::ReadNextData(){_singleData.clear();_mark = _markVector[_index];for (int i = 0; i < _data[_index].size(); i++){_singleData.push_back(_data[_index][i]);//std::cout << _data[_index].size() << std::endl;}_singleData.push_back(1);/*for (int i = 0; i < _singleData.size(); i ++){using namespace std;cout << _singleData[i] << "  ";}std::cout << std::endl;*/_index++;return true; }bool PLA::Train(unsigned long int loop){unsigned long int error_pre = 10000000;int count = 0;bool pokeFlag = false;std::vector<double> wTemp;for (unsigned long int i = 0; i < loop; i++){unsigned long int error = 0;_index = 0;//std::cout << "dataSum " << _dataSum << std::endl;for (int j = 0; j < _dataSum; j++){ReadNextData();if (!Perce(1, -1)) error++;}if (error > 1){if (error < error_pre){error_pre = error;wTemp.clear();for (int len = 0; len < _w.size(); len++)wTemp.push_back(_w[len]);std::cout << error_pre << std::endl;pokeFlag = true;_pokePos = i;_pokeErrors = error;}}else{pokeFlag = false;break;}//std::cout << error << std::endl;}if (pokeFlag){_w.clear();for (int i = 0; i < wTemp.size(); i++)_w.push_back(wTemp[i]);}_pokeFlag = pokeFlag;return pokeFlag;}

错误之处,还望指出!

原创粉丝点击