//支持向量机给出的上一篇文章的学习结果


#include <iostream>
using namespace std;
//判别函数
int Sign(double a)
{
  if(a>=0) return 1;
  else return -1;
}

//感知器输出函数
double outputLayer(double* w , double *p)
{
  return w[0]*p[0]+w[1]*p[1]+w[2];
}
////初始网络参数(二维向量)
//double weight[3]={1,1,1};
//样本数
int n=4;
//样本
double inputLayer[4][2]={{5,1},{10,5},{1,10},{10,1}};
//先验信息标签即分类输出
//int label[4]={1,1,1,-1};

//学习速度
double yita=0.1;
double amendW( double w,double e,double p,double yita)
{
  return w+yita*e*p;
}

double amendE( double b,double e,double yita)
{
  return b+yita*e;
}

double errorr=0;

void main()
{
  int label[4]={1,1,1,-1};
//初始网络参数(二维向量)
  double weight[3]={1,1,1};
  int dimention=2;
  double error;
  double output[4];//= new double [n];
  int discriminant[4];// = new int [n];

  bool stop[5];//=new bool [n+1];

  for(int i=0;i<n+1;i++)
  { stop[i]=false;}

  int k=0;
  while(stop[n]==false)
  {
    for(int ii=k;ii<k+n;ii++)
    {
      int i=ii%n;
      bool changed=false;
      static int count=0;
      while(stop[i]==false)
      {
        output[i]= outputLayer(weight,inputLayer[i]);
        discriminant[i]=Sign( output[i]);
        stop[i]=(discriminant[i]==label[i]);
        if(stop[i]){break;}

        error=label[i]-discriminant[i];
        for(int m=0;m<dimention;m++)
          weight[m]=amendW(weight[m],error,inputLayer[i][m],yita);

        weight[2]=amendE(weight[2],error,yita);
        changed=true;
        //cout<<count++<</*" error:"<<error<<*/endl;

      }
      if(changed)
      {
        for(int iii=1;iii<n;iii++)
        stop[(iii+i)%n]=false;
        k=(ii+1)%n;
        break;
      }
    }

    stop[n]=stop[0];
    for(int i=0;i<n;i++)
    stop[n]=stop[n]&&stop[i];

  }

 

  //支持向量机给出的结果

  double minPositiveDistance=10000, minNegativeDistance=-10000;//初始化距离标准值

  double distance[4];//正常应该求输入点集的凸包顶点,用定点求解最合适,本文样本少,目的在于理解支持向量机

  int pPoint=0,nPoint=0;//正负距离的支持向量点编号

  for(int i=0;i<n;i++)
  {
    distance[i]=(weight[0]*inputLayer[i][0]+weight[1]*inputLayer[i][1]+weight[2])/sqrt(weight[0]*weight[0]+weight[1]*weight[1]);
    if(distance[i]>=0)
    {
      if(minPositiveDistance>distance[i])
      {
        minPositiveDistance=distance[i];
        pPoint=i;
      }
    }
    else
    {
      if(minNegativeDistance<distance[i])
      {
        minNegativeDistance=distance[i];
        nPoint=i;
      }
    }
  }

  double medium=fabs(minPositiveDistance-minNegativeDistance)/2;
  medium=medium-minPositiveDistance;
  double slope=-weight[0]/weight[1];
  double cosalpha=1.0/(sqrt(1+slope*slope));

  weight[2]=weight[2]/weight[1]+medium/cosalpha;
  weight[0]=-slope;
  weight[1]=1;


  //求另一条直线
  double slope2=(inputLayer[pPoint][1]-inputLayer[nPoint][1])/(double)(inputLayer[pPoint][0]-inputLayer[nPoint][0]);

  double x0,y0;//超平面旋转点

  x0=(slope2*inputLayer[nPoint][0]-inputLayer[nPoint][1]-weight[2])/(slope2+weight[0]);
  y0=-weight[0]*x0-weight[2];

  double distance0=fabs(minPositiveDistance-minNegativeDistance);
  double alpha0=atan(slope);
  double alpha1=atan(slope2);
  double dertal=3.1415926/180.0;

  if(alpha0>alpha1)
  {
    for(double alpha=alpha0+dertal;alpha>alpha1;alpha-=dertal)
    {
      weight[0]=-tan(alpha);
      weight[2]=-weight[0]*x0-y0;

      int i=pPoint;
      double pDistanceNew=(weight[0]*inputLayer[i][0]+weight[1]*inputLayer[i][1]+weight[2])/sqrt(weight[0]*weight[0]+weight[1]*weight[1]);

      i=nPoint;
      double nDistanceNew=(weight[0]*inputLayer[i][0]+weight[1]*inputLayer[i][1]+weight[2])/sqrt(weight[0]*weight[0]+weight[1]*weight[1]);

      double d=fabs( pDistanceNew-nDistanceNew);

      if(distance0<d)
      {
        distance0=d;
      }
      else
      {
        weight[0]=-tan(alpha-dertal);
        weight[2]=-weight[0]*x0-y0;
        break;
      }
    }
  }
  else
  {
    for(double alpha=alpha0+dertal;alpha<alpha1;alpha+=dertal)
    {
      weight[0]=-tan(alpha);
      weight[2]=-weight[0]*x0-y0;

      int i=pPoint;
      double pDistanceNew=(weight[0]*inputLayer[i][0]+weight[1]*inputLayer[i][1]+weight[2])/sqrt(weight[0]*weight[0]+weight[1]*weight[1]);

      i=nPoint;
      double nDistanceNew=(weight[0]*inputLayer[i][0]+weight[1]*inputLayer[i][1]+weight[2])/sqrt(weight[0]*weight[0]+weight[1]*weight[1]);

      double d=fabs( pDistanceNew-nDistanceNew);

      if(distance0<d)
      {
        distance0=d;
      }
      else
      {
        weight[0]=-tan(alpha-dertal);
        weight[2]=-weight[0]*x0-y0;
        break;
      }
    }
  }

}

 

前面感知机给出结果后,支持向量机计算超平面对目标进行分类;样本是线性可分的。不可分情况要还原数据到高维度空间去分析,数据可分类的最小维度就是原始数据的降维投影到该空间后能够分开的维度。从黑色结果输出图中可见支持向量机给出的结果比感知器结果提高了。

posted on 2017-12-10 02:27  老穆  阅读(752)  评论(0)    收藏  举报