参考博客 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的距离为:

其中,||w||为w的L2范数。

 其次,对于误分类点来说,当-y(wxi + b)>0时,yi=-1,当-yi(wxi + b)<0时,yi=+1。所以对误分类点(xi, yi)满足:

-y(wxi +b) > 0

所以误分类点(xi, yi)到分类超平面S的距离是:

3. 感知机算法

感知机学习问题转化为求解损失函数式(1)的最优化问题,最优化的方法是随机梯度下降法。感知机学习算法是误分类驱动的,具体采用随机梯度下降法。首先,任意选取一个超平面w0,b0,然后用梯度下降法不断极小化目标函数式(1)。极小化的过程不是一次使M中所有误分类点的梯度下降,而是一次随机选取一个误分类点使其梯度下降。

   损失函数L(w,b)的梯度是对w和b求偏导,即:
其中,(0<<=1)是学习率,即学习的步长。
随机梯度下降法:假如你站在曲面的一点,要以最快的速度到达最低点,当然会沿着坡度最大的方向往下走(梯度的反方向)
综上,感知机学习算法如下:
算法1 感知机学习算法的原始形式

原始形式C++实现的源代码

 #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 ;
double res = ;
for(int i = ; i < a.size(); ++ i){
res +=a[i]*b[i];
}
return res;
} //感知机模型类
class Preception{
public:
Preception(int iters = ,int learnRate = ,double initw = , double initb = ){
iterators = iters;
w.push_back(initw);
b = initb;
step = learnRate;
} ~Preception(){
w.clear();
b = ;
} //训练数据
//如果迭代次数完,还没有找到w和b, 则认为数据集不是线性可分的,返回false
//如果找到了w和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()); for(int iter = ; iter < iterators; ++ iter){
bool flag = true;
for(int i = ; i < train_x.size();){
if( (dot_product(w,train_x[i]) + b)*(double)train_y[i] <= ){
update(train_x[i],train_y[i]);
flag = false;
}else{
++i;
}
}
if(flag) return true;
}
return false;
} //批量预测数据
std::vector<int> predict(std::vector<std::vector<double> >& data_x){
std::vector<int> ret;
for(int i = ; 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,w)+ b > ? : -;
} //打印感知机模型
void printPreceptronModel(){
std::cout<<"原始形式感知机模型:f(x)=sign(";
for(int i = ; i < w.size(); ++ i){
if( i ) std::cout<<"+";
if(w[i]!=) std::cout<<w[i];
std::cout<<"x"<<i+;
}
if(b > ) std::cout<<"+";
std::cout<<b<<")"<<std::endl;
} private:
//初始化向量w的维数
void initWeight(int size){
for(int i = ; i < size; ++ i){
w.push_back(w[]);
}
} //更新w和b
void update(std::vector<double>& x, double y){
for(int i = ; i < w.size(); ++ i){
w[i] += step*y*x[i];
}
b += step*y; // for(int i = 0 ; i < w.size(); ++ i)
// std::cout<<w[i]<<",";
// std::cout<<std::endl; // std::cout<<b<<std::endl;
} private:
int iterators; //迭代次数 //f(x) = sign(wx+b)
std::vector<double> w; //注意w是向量
double b; double step; //学习速率
}; int main(){
std::vector<std::vector<double> >test_x();
test_x[].push_back();test_x[].push_back();
test_x[].push_back();test_x[].push_back();
test_x[].push_back();test_x[].push_back();
std::vector<int> test_y();
test_y[] = ;
test_y[] = ;
test_y[] = -; Preception *model = new Preception();
model->train(test_x,test_y);
model->printPreceptronModel();
}

感知机算法的原始形式

算法2 感知机学习算法的对偶形式
对偶形式的基本想法是,将w和b表示为实例xi和标记yi的线性组合形式,通过求解其系数而求得w和b。对误分类点(xi, yi)通过
所以,感知机学习算法的对偶形式如下:

对偶形式C++实现的源代码

 #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 ;
double res = ;
for(int i = ; i < a.size(); ++ i){
res +=a[i]*b[i];
}
return res;
} //感知机模型类
class Preception{
public:
Preception(int iters = ,int learnRate = ,double initw = , double initb = ){
iterators = iters;
a.push_back(initw);
b = initb;
step = learnRate;
} ~Preception(){
a.clear();
b = ;
} //训练数据
//如果迭代次数完,还没有找到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 = ; i < a.size(); ++ i){
int iter = ;
while(iter < iterators){
double sum = b;
for(int j = ; j < a.size(); ++ j){
sum += a[j]*train_y[j]*gram[j][i];
}
sum *= train_y[i];
if(sum <= ) 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 = ; 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 > ? : -;
} //打印感知机模型
void printPreceptronModel(){
std::cout<<"原始形式感知机模型:f(x)=sign(";
for(int i = ; i < a.size(); ++ i){
if( i ) std::cout<<"+";
if(a[i]!=) std::cout<<a[i];
std::cout<<"x"<<i+;
}
if(b > ) std::cout<<"+";
std::cout<<b<<")"<<std::endl;
} private:
//初始化向量a的维数
void initWeight(int size){
for(int i = ; i < size; ++ i){
a.push_back(a[]);
}
} //生成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,));
for(int i = ; i < n ; ++ i){
for(int j = ; 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] +=;
b += step*y;
} private:
int iterators; //迭代次数 std::vector<double> a; //注意w是向量
double b; double step; //学习速率
}; int main(){
std::vector<std::vector<double> >test_x();
test_x[].push_back();test_x[].push_back();
test_x[].push_back();test_x[].push_back();
test_x[].push_back();test_x[].push_back();
std::vector<int> test_y();
test_y[] = ;
test_y[] = ;
test_y[] = -; Preception *model = new Preception();
model->train(test_x,test_y);
model->printPreceptronModel();
}

感知机学习算法的对偶形式

统计学习方法 --- 感知机模型原理及c++实现的更多相关文章

  1. [笔记-统计学习方法]感知机模型(perceptron) 原理与实现

    前几天认把感知机这一章读完了,顺带做了点笔记 现在把笔记做第三次的整理 (不得不说博客园的LaTex公式和markdown排版真的不太舒服,该考虑在服务器上建一个博客了) 零.总结 适用于具有线性可分 ...

  2. 统计学习方法 | 感知机 | python实现

    感知机是二类分类的线性分类模型,利用随机梯度下降法对基于误分类的损失函数进行极小化. 书中算法可以将所有样本和系数向量写成增广向量的形式,并将所有负样本乘以-1,统一形式,方便计算. (1)训练数据集 ...

  3. 统计学习方法与Python实现(一)——感知机

    统计学习方法与Python实现(一)——感知机 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 假设输入的实例的特征空间为x属于Rn的n维特征向量, ...

  4. 统计学习方法6—logistic回归和最大熵模型

    目录 logistic回归和最大熵模型 1. logistic回归模型 1.1 logistic分布 1.2 二项logistic回归模型 1.3 模型参数估计 2. 最大熵模型 2.1 最大熵原理 ...

  5. 《统计学习方法》极简笔记P2:感知机数学推导

    感知机模型 输入空间是$\chi\subseteq\mathbb{R}^n$,输出空间是$y={+1,-1}$ 感知机定义为:$f(x)=sign(wx+b)$ 感知机学习策略 输入空间任一点$x_0 ...

  6. 统计学习方法:罗杰斯特回归及Tensorflow入门

    作者:桂. 时间:2017-04-21  21:11:23 链接:http://www.cnblogs.com/xingshansi/p/6743780.html 前言 看到最近大家都在用Tensor ...

  7. 统计学习方法—SVM推导

    目录 SVM 1. 定义 1.1 函数间隔和几何间隔 1.2 间隔最大化 2. 线性可分SVM 2.1 对偶问题 2.2 序列最小最优算法(SMO) 3. 线性不可分SVM 3.1 松弛变量 3.2 ...

  8. word2vec模型原理与实现

    word2vec是Google在2013年开源的一款将词表征为实数值向量的高效工具. gensim包提供了word2vec的python接口. word2vec采用了CBOW(Continuous B ...

  9. 李航《统计学习方法》CH01

    CH01 统计学方法概论 前言 章节目录 统计学习 监督学习 基本概念 问题的形式化 统计学习三要素 模型 策略 算法 模型评估与模型选择 训练误差与测试误差 过拟合与模型选择 正则化与交叉验证 正则 ...

随机推荐

  1. 复习(2)【postman,charles,filezilla server】

    Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件.通常我们可以用它来测试接口. Charles是在Mac下常用的网络封包截取工具,在做移动开发时,我们为了调试与服务器端的 ...

  2. angularJS绑定数据时自动转义html标签

    angularJS在进行数据绑定时默认是会以文本的形式输出,也就是对你数据中的html标签不进行转义照单全收,这样提高了安全性,防止了html标签中的注入攻击,但有些时候还是需要的,特别是从数据库读取 ...

  3. SDK,API,DLL名词解释

    SDK (software devalopment kit) 软件开发工具包 : 一般都是一些软件工程师Wie特定的软件包.软件框架.硬件平台.操作系统等建立应用软件时的开发工具的集合. API (A ...

  4. Burp Suite新手指南

    Burp Suite想必大家都用过,但是大家未必知道它的所有功能.因此,本文的主要目的就是尽量深入介绍各种功能.BurpSuite有以下这些功能: 截获代理– 让你审查修改浏览器和目标应用间的流量. ...

  5. Gridview中运用CommandField 删除控件时注意点

    我在gridview1 <编辑列>里面添加了一个<CommandField 删除>的控件,之后在gridview1的事件<RowDeleting>事件下 写了一段删 ...

  6. Mac下配置Apache + Php + Mysql环境

    Apache与PHP的配置 Mavericks同以往的OSX一样自带了apache2.2.24和php5.4.17,但默认情况下没有开启,打开终端 sudo apachectl start 这时在浏览 ...

  7. MySQL主从同步

    脚本 [root@test scripts]# cat ss.sh #!/bin/bash . /etc/init.d/functions MYUSER=root MYPASS=c565f972 SO ...

  8. Battleships in a Board

    Given an 2D board, count how many different battleships are in it. The battleships are represented w ...

  9. iOS SpriteKit 问题

    今天偶然发现 向SKShapeNode添加子 node时,子node参考的是 SKShapeNode的parent的坐标系,但是如果使用SKSpriteNode却是使用自己的坐标系,带研究.而且sha ...

  10. ASCII码、Unicode码 转中文

    ASCII码.Unicode码 转中文 在最近工作中遇到了一些汉字编码转换的处理,可以通过正则表达式及转换字符来实现转成中文 Unicode转换示例 通常为10位编码, 通过digit参数传入 pri ...