您的位置:首页 > 编程语言 > C语言/C++

统计学习方法 --- 感知机模型原理及c++实现

2014-12-25 21:34 465 查看
参考博客 Liam Q博客 和李航的《统计学习方法》

感知机学习旨在求出将训练数据集进行线性划分的分类超平面,为此,导入了基于误分类的损失函数,然后利用梯度下降法对损失函数进行极小化,从而求出感知机模型。感知机模型是神经网络和支持向量机的基础。下面分别从感知机学习的模型、策略和算法三个方面来介绍。

1. 感知机模型

感知机模型如下:

f(x)= sign(w*x+b)

其中,x为输入向量,sign为符号函数,括号里面大于等于0,则其值为1,括号里面小于0,则其值为-1。w为权值向量,b为偏置。求感知机模型即求模型参数w和b。感知机预测,即通过学习得到的感知机模型,对于新的输入实例给出其对应的输出类别1或者-1。

2. 感知机策略

假设训练数据集是线性可分的,感知机学习的目标就是求得一个能够将训练数据集中正负实例完全分开的分类超平面,为了找到分类超平面,即确定感知机模型中的参数w和b,需要定义一个损失函数并通过将损失函数最小化来求w和b。

这里选择的损失函数是误分类点到分类超平面S的总距离。输入空间中任一点x0到超平面S的距离为:

#include <iostream>
#include <vector>
#include <algorithm>

#define random(x) (rand()%(x))

//向量的点积
double dot_product(std::vector<double>& a, std::vector<double>& b){
if(a.size() != b.size()) return 0;
double res = 0;
for(int i = 0 ; i < a.size(); ++ i){
res +=a[i]*b[i];
}
return res;
}

//感知机模型类
class Preception{
public:
Preception(int iters = 100,int learnRate = 1,double initw = 0, double initb = 0){
iterators = iters;
a.push_back(initw);
b = initb;
step = learnRate;
}

~Preception(){
a.clear();
b = 0;
}

//训练数据
//如果迭代次数完,还没有找到a和b, 则认为数据集不是线性可分的,返回false
//如果找到了a和b,则认为数据集是线性可分的,返回true
bool train(std::vector<std::vector<double> >& train_x,std::vector<int>& train_y){
if(train_x.size() != train_y.size()) return false;
initWeight(train_x.size());
std::vector<std::vector<double> > gram = productGram(train_x);
for(int i = 0 ; i < a.size(); ++ i){
int iter = 0;
while(iter < iterators){
double sum = b;
for(int j = 0; j < a.size(); ++ j){
sum += a[j]*train_y[j]*gram[j][i];
}
sum *= train_y[i];
if(sum <= 0) update(i,train_y[i]);
else break;
++iter;
}
if(iter >= iterators) return false;
}
return true;
}

//批量预测数据
std::vector<int> predict(std::vector<std::vector<double> >& data_x){
std::vector<int> ret;
for(int i = 0 ; i < data_x.size(); ++ i){
ret.push_back(predict(data_x[i]));
}
return ret;
}

//预测x
int predict(std::vector<double>& x){
return dot_product(x,a)+ b > 0 ? 1 : -1;
}

//打印感知机模型
void printPreceptronModel(){
std::cout<<"原始形式感知机模型:f(x)=sign(";
for(int i = 0 ; i < a.size(); ++ i){
if( i ) std::cout<<"+";
if(a[i]!=1) std::cout<<a[i];
std::cout<<"x"<<i+1;
}
if(b > 0) std::cout<<"+";
std::cout<<b<<")"<<std::endl;
}

private:
//初始化向量a的维数
void initWeight(int size){
for(int i = 1; i < size; ++ i){
a.push_back(a[0]);
}
}

//生成Gram矩阵
std::vector<std::vector<double> > productGram(std::vector<std::vector<double> >& train_x){
int n = train_x.size();
std::vector<std::vector<double> > gram(n, std::vector<double>(n,0));
for(int i = 0 ; i < n ; ++ i){
for(int j = 0 ; j  < n; ++ j){
gram[i][j] = dot_product(train_x[i], train_x[j]);
}
}
return gram;
}

//更新w和b
void update(int index, double y){
a[index] +=1;
b += step*y;
}

private:
int iterators;          //迭代次数

std::vector<double> a;    //注意w是向量
double b;

double step;  //学习速率
};

int main(){
std::vector<std::vector<double> >test_x(3);
test_x[0].push_back(3);test_x[0].push_back(3);
test_x[1].push_back(4);test_x[1].push_back(3);
test_x[2].push_back(1);test_x[2].push_back(1);
std::vector<int> test_y(3);
test_y[0] = 1;
test_y[1] = 1;
test_y[2] = -1;

Preception *model = new Preception();
model->train(test_x,test_y);
model->printPreceptronModel();
}


感知机学习算法的对偶形式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: