感知器算法

来源:互联网 发布:火炬之光2mac版本更新 编辑:程序博客网 时间:2024/06/02 10:37

感知器算法由 Rosenblatt 提出,其主要功能是通过设计分类器来判别样本所属的类别;通过对训练样本集的学习,从而得到判别函数权值的解,产生线性可分的样本判别函数。该算法属于非参数算法,优点是不需要对各类样本的统计性质作任何假设,属于确定性方法。

感知器算法是非常好的二分类在线算法。该算法求取一个分离超平面,超平面由w∈R  参数化并用来预测。对于一个样本x,感知器算法通过计算y=(wx)预测样本的标签。最终的预测标签通过计算sign(y)来实现。算法仅在预测错误时修正权值w 。如果正确的标签是 y =1,那么权值修正为w +x;如果y =−1 ,权值变为w −x ,可以总结为 w←w +yx;需要注意的是在预测后,尽管算法不能保证修正后的预测准则会正确分类目前的样本,但在目前样本上的分离超平面的间隔会增加,即算法是保守的不是主动的。

算法流程图如下所示:


算法步骤:


2.  感知器算法的实现

我是用Java语言来编写的,实现的比较简单的两类,两特征的感知器算法。该算法的目的是为了计算权向量W。程序开始时输入样本数N,然后程序随机产生N个样本值。


根据感知器算法的过程,程序在进行了15次计算后得到了最终的权向量W=(10,-2,-12)。所以线性分类判别函数是10x-2y-12=0,化简得y=5x-6。为验证该函数是否能正确分类,故把所有的样本值点在XOY平面标出来,并画出y=5x-6的函数图象,结果如下所示:


从上图中可以看出,该判别函数很好地把两类数据分开了,得到的结果还是比较准确的。

源代码:

import java.io.IOException;import java.util.Scanner;public class Perceptron {public static void main(String[] args) throws IOException {int N,C=1,t=1;//N是训练样本数,C是迭代过程中的系数,t为迭代次数int[] W=new int[]{-1,1,0};//权向量W,初始设为(-1,1,0)int[] temp=new int[3];//作为与上一次迭代的W做比较System.out.println("输入样本数");Scanner strin=new Scanner(System.in);N=strin.nextInt();//输入样本数,随后产生随机样本int[][] X=new int[4][N];//样本值genesample(X);//第一次迭代,System.arraycopy(W, 0, temp, 0, W.length);//数组的深度复制for(int i=0;i<N;i++){W=panduan(W,X,i,C);}System.out.println("第1次迭代后权向量W是:");arrayout(W);//继续迭代while(!arrayequal(temp,W)){//如果不相等继续迭代计算System.arraycopy(W, 0, temp, 0, W.length);//数组的赋值用此方法有效t++;for(int i=0;i<N;i++){W=panduan(W,X,i,C);}System.out.println("第"+t+"次迭代后权向量W是:");arrayout(W);}System.out.println("经过"+t+"次迭代后权向量W是:");arrayout(W);}//产生随机样本,是一个4*n的矩阵,1,2表示该样本的特征值,3代表增1矩阵值,4代表该样本所属的分类public static void genesample(int[][] X){for(int i=0;i<2;i++){//产生样本特征值for(int j=0;j<X[1].length;j++){X[i][j]=(int)(Math.random()*10);}}for(int m=0;m<X[1].length;m++){//增1矩阵X[2][m]=1;}for(int k=0;k<X[1].length;k++){//产生样本所属的类别1和2String chars = "12";X[3][k]=Integer.parseInt(String.valueOf(chars.charAt((int)(Math.random()*2))));}System.out.println("产生的样本值如下所示");for(int a=0;a<4;a++){//输出产生的样本for(int b=0;b<X[1].length;b++){System.out.print(X[a][b]+" ");}System.out.println();}}//计算Wk*Xk的值,即第k+1个样本值X与W的乘积    public static int calculate(int[] W,int[][] X,int i){    int a=0;    for(int j=0;j<W.length;j++){    a=W[j]*X[j][i]+a;    }    return a;}      //判断Wk*Xk的值,并做出修正,"必须要返回数组类型"    public static int[] panduan(int[] W,int[][] X,int k,int C){    if(calculate(W,X,k)<=0&&X[3][k]==1){//Xk属于第一类,且Wk*Xk<=0,修正Wk的值,并重新计算    for(int i=0;i<W.length;i++){    W[i]=W[i]+C*X[i][k];    }    }    if(calculate(W,X,k)>=0&&X[3][k]==2){//Xk属于第二类,且Wk*Xk>=0,修正Wk的值    for(int i=0;i<W.length;i++){    W[i]=W[i]-C*X[i][k];    }    }    return W;}        //判断两个int数组是否相等    public static Boolean arrayequal(int[] W1,int[] W2){    Boolean flag=true;    for(int i=0;i<W1.length;i++){    if(W1[i]!=W2[i]){    flag=false;    break;    }       }    return flag;    }      //输出W的值    public static void arrayout(int[] W){    for(int k=0;k<W.length;k++){System.out.print(W[k]+" ");}    System.out.println();    }}



0 0
原创粉丝点击