感知器算法

感知器算法由 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和2
			String 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();
    }

}



  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值